示例#1
0
CURLcode Curl_telnet(struct connectdata *conn)
{
  CURLcode code;
  struct SessionHandle *data = conn->data;
  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
#if defined(WIN32) || defined(WIN64)
  HMODULE wsock2;
  WSOCK2_FUNC close_event_func;
  WSOCK2_FUNC create_event_func;
  WSOCK2_FUNC event_select_func;
  WSOCK2_FUNC enum_netevents_func;
  WSAEVENT event_handle;
  WSANETWORKEVENTS events;
  HANDLE stdin_handle;
  HANDLE objs[2];
  DWORD waitret;
  DWORD readfile_read;
#else
  fd_set readfd;
  fd_set keepfd;
#endif
  ssize_t nread;  
  bool keepon = TRUE;
  char *buf = data->state.buffer;
  struct TELNET *tn;

  code = init_telnet(conn);
  if(code)
    return code;

  tn = (struct TELNET *)conn->proto.telnet;

  code = check_telnet_options(conn);
  if(code)
    return code;

#if defined(WIN32) || defined(WIN64)
  /*
  ** This functionality only works with WinSock >= 2.0.  So,
  ** make sure have it.
  */
  code = check_wsock2(data);
  if (code)
    return code;

  /* OK, so we have WinSock 2.0.  We need to dynamically */
  /* load ws2_32.dll and get the function pointers we need. */
  wsock2 = LoadLibrary("WS2_32.DLL");
  if (wsock2 == NULL) {
    failf(data,"failed to load WS2_32.DLL (%d)",GetLastError());
    return CURLE_FAILED_INIT;
  }

  /* Grab a pointer to WSACreateEvent */
  create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
  if (create_event_func == NULL) {
    failf(data,"failed to find WSACreateEvent function (%d)",
	  GetLastError());
    FreeLibrary(wsock2);
    return CURLE_FAILED_INIT;
  }

  /* And WSACloseEvent */
  close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
  if (create_event_func == NULL) {
    failf(data,"failed to find WSACloseEvent function (%d)",
	  GetLastError());
    FreeLibrary(wsock2);
    return CURLE_FAILED_INIT;
  }

  /* And WSAEventSelect */
  event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
  if (event_select_func == NULL) {
    failf(data,"failed to find WSAEventSelect function (%d)",
	  GetLastError());
    FreeLibrary(wsock2);
    return CURLE_FAILED_INIT;
  }

  /* And WSAEnumNetworkEvents */
  enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
  if (enum_netevents_func == NULL) {
    failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
	  GetLastError());
    FreeLibrary(wsock2);
    return CURLE_FAILED_INIT;
  }

  /* We want to wait for both stdin and the socket. Since
  ** the select() function in winsock only works on sockets
  ** we have to use the WaitForMultipleObjects() call.
  */

  /* First, create a sockets event object */
  event_handle = (WSAEVENT)create_event_func();
  if (event_handle == WSA_INVALID_EVENT) {
    failf(data,"WSACreateEvent failed (%d)",WSAGetLastError());
    FreeLibrary(wsock2);
    return CURLE_FAILED_INIT;
  }

  /* The get the Windows file handle for stdin */
  stdin_handle = GetStdHandle(STD_INPUT_HANDLE);

  /* Create the list of objects to wait for */
  objs[0] = stdin_handle;
  objs[1] = event_handle;

  /* Tell winsock what events we want to listen to */
  if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
    close_event_func(event_handle);
    FreeLibrary(wsock2);
    return 0;
  }

  /* Keep on listening and act on events */
  while(keepon) {
    waitret = WaitForMultipleObjects(2, objs, FALSE, INFINITE);
    switch(waitret - WAIT_OBJECT_0) {
    case 0:
    {
      unsigned char outbuf[2];
      int out_count = 0;
      ssize_t bytes_written;
      char *buffer = buf;
              
      if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
                   &readfile_read, NULL)) {
        keepon = FALSE;
        break;
      }
      nread = readfile_read;
        
      while(nread--) {
        outbuf[0] = *buffer++;
        out_count = 1;
        if(outbuf[0] == CURL_IAC)
          outbuf[out_count++] = CURL_IAC;
          
        Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
                   out_count, &bytes_written);
      }
    }
    break;
      
    case 1:
      if(enum_netevents_func(sockfd, event_handle, &events)
         != SOCKET_ERROR) {
        if(events.lNetworkEvents & FD_READ) {
          /* This reallu OUGHT to check its return code. */
          (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
            
          telrcv(conn, (unsigned char *)buf, nread);
          
          fflush(stdout);
            
          /* Negotiate if the peer has started negotiating,
             otherwise don't. We don't want to speak telnet with
             non-telnet servers, like POP or SMTP. */
          if(tn->please_negotiate && !tn->already_negotiated) {
            negotiate(conn);
            tn->already_negotiated = 1;
          }
        }
          
        if(events.lNetworkEvents & FD_CLOSE) {
          keepon = FALSE;
        }
      }
      break;
    }
  }

  /* We called WSACreateEvent, so call WSACloseEvent */
  if (close_event_func(event_handle) == FALSE) {
    infof(data,"WSACloseEvent failed (%d)",WSAGetLastError());
  }

  /* "Forget" pointers into the library we're about to free */
  create_event_func = NULL;
  close_event_func = NULL;
  event_select_func = NULL;
  enum_netevents_func = NULL;

  /* We called LoadLibrary, so call FreeLibrary */
  if (!FreeLibrary(wsock2))
    infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError());
#else
  FD_ZERO (&readfd);		/* clear it */
  FD_SET (sockfd, &readfd);
  FD_SET (0, &readfd);

  keepfd = readfd;

  while (keepon) {
    struct timeval interval;

    readfd = keepfd;		/* set this every lap in the loop */
    interval.tv_sec = 1;
    interval.tv_usec = 0;

    switch (select (sockfd + 1, &readfd, NULL, NULL, &interval)) {
    case -1:			/* error, stop reading */
      keepon = FALSE;
      continue;
    case 0:			/* timeout */
      break;
    default:			/* read! */
      if(FD_ISSET(0, &readfd)) { /* read from stdin */
        unsigned char outbuf[2];
        int out_count = 0;
        ssize_t bytes_written;
        char *buffer = buf;
        
        nread = read(0, buf, 255);

        while(nread--) {
          outbuf[0] = *buffer++;
          out_count = 1;
          if(outbuf[0] == CURL_IAC)
            outbuf[out_count++] = CURL_IAC;
      
          Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
                     out_count, &bytes_written);
        }
      }

      if(FD_ISSET(sockfd, &readfd)) {
        /* This OUGHT to check the return code... */
        (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);

        /* if we receive 0 or less here, the server closed the connection and
           we bail out from this! */
        if (nread <= 0) {
          keepon = FALSE;
          break;
        }

        telrcv(conn, (unsigned char *)buf, nread);

        /* Negotiate if the peer has started negotiating,
           otherwise don't. We don't want to speak telnet with
           non-telnet servers, like POP or SMTP. */
        if(tn->please_negotiate && !tn->already_negotiated) {
          negotiate(conn);
          tn->already_negotiated = 1;
        }
      }
    }
    if(data->set.timeout) {
      struct timeval now;           /* current time */
      now = Curl_tvnow();
      if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) {
        failf(data, "Time-out");
        code = CURLE_OPERATION_TIMEOUTED;
        keepon = FALSE;
      }
    }
  }
#endif
  /* mark this as "no further transfer wanted" */
  Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);

  return code;
}
示例#2
0
CURLcode Curl_dict(struct connectdata *conn)
{
  char *word;
  char *ppath;
  char *database = NULL;
  char *strategy = NULL;
  char *nthdef = NULL; /* This is not part of the protocol, but required
                          by RFC 2229 */
  CURLcode result=CURLE_OK;
  struct SessionHandle *data=conn->data;
  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];

  char *path = conn->path;
  curl_off_t *bytecount = &conn->bytecount;

  if(conn->bits.user_passwd) {
    /* AUTH is missing */
  }

  if (strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
      strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
      strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
      
    word = strchr(path, ':');
    if (word) {
      word++;
      database = strchr(word, ':');
      if (database) {
        *database++ = (char)0;
        strategy = strchr(database, ':');
        if (strategy) {
          *strategy++ = (char)0;
          nthdef = strchr(strategy, ':');
          if (nthdef) {
            *nthdef++ = (char)0;
          }
        }
      }
    }
      
    if ((word == NULL) || (*word == (char)0)) {
      failf(data, "lookup word is missing");
    }
    if ((database == NULL) || (*database == (char)0)) {
      database = (char *)"!";
    }
    if ((strategy == NULL) || (*strategy == (char)0)) {
      strategy = (char *)".";
    }
      
    result = Curl_sendf(sockfd, conn,
                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
                        "MATCH "
                        "%s "    /* database */
                        "%s "    /* strategy */
                        "%s\n"   /* word */
                        "QUIT\n",
                        
                        database,
                        strategy,
                        word
                        );
    if(result)
      failf(data, "Failed sending DICT request");
    else
      result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
                             -1, NULL); /* no upload */      
    if(result)
      return result;
  }
  else if (strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
           strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
           strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
    
    word = strchr(path, ':');
    if (word) {
      word++;
      database = strchr(word, ':');
      if (database) {
        *database++ = (char)0;
        nthdef = strchr(database, ':');
        if (nthdef) {
          *nthdef++ = (char)0;
        }
      }
    }
      
    if ((word == NULL) || (*word == (char)0)) {
      failf(data, "lookup word is missing");
    }
    if ((database == NULL) || (*database == (char)0)) {
      database = (char *)"!";
    }
      
    result = Curl_sendf(sockfd, conn,
                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
                        "DEFINE "
                        "%s "     /* database */
                        "%s\n"    /* word */
                        "QUIT\n",
                        database,
                        word);
    if(result)
      failf(data, "Failed sending DICT request");
    else
      result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
                             -1, NULL); /* no upload */
    
    if(result)
      return result;
      
  }
  else {
      
    ppath = strchr(path, '/');
    if (ppath) {
      int i;
	
      ppath++;
      for (i = 0; ppath[i]; i++) {
        if (ppath[i] == ':')
          ppath[i] = ' ';
      }
      result = Curl_sendf(sockfd, conn,
                          "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
                          "%s\n"
                          "QUIT\n", ppath);
      if(result)
        failf(data, "Failed sending DICT request");
      else
        result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
                               -1, NULL);
      if(result)
        return result;
    }
  }

  return CURLE_OK;
}
示例#3
0
文件: ldap.c 项目: newobj/taz
CURLcode Curl_ldap(struct connectdata *conn)
{
  CURLcode status = CURLE_OK;
  int rc;
  void *(*ldap_open)(char *, int);
  int (*ldap_simple_bind_s)(void *, char *, char *);
  int (*ldap_unbind_s)(void *);
  int (*ldap_url_search_s)(void *, char *, int, void **);
  void *(*ldap_first_entry)(void *, void *);
  void *(*ldap_next_entry)(void *, void *);
  char *(*ldap_err2string)(int);
  int (*ldap_entry2text)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long);
  int (*ldap_entry2html)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long, char *, char *);
  void *server;
  void *result;
  void *entryIterator;

  int ldaptext;
  struct SessionHandle *data=conn->data;
  
  infof(data, "LDAP: %s\n", data->change.url);

  DynaOpen();
  if (libldap == NULL) {
    failf(data, "The needed LDAP library/libraries couldn't be opened");
    return CURLE_LIBRARY_NOT_FOUND;
  }

  ldaptext = data->set.ftp_ascii; /* This is a dirty hack */
  
  /* The types are needed because ANSI C distinguishes between
   * pointer-to-object (data) and pointer-to-function.
   */
  DYNA_GET_FUNCTION(void *(*)(char *, int), ldap_open);
  DYNA_GET_FUNCTION(int (*)(void *, char *, char *), ldap_simple_bind_s);
  DYNA_GET_FUNCTION(int (*)(void *), ldap_unbind_s);
  DYNA_GET_FUNCTION(int (*)(void *, char *, int, void **), ldap_url_search_s);
  DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_first_entry);
  DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_next_entry);
  DYNA_GET_FUNCTION(char *(*)(int), ldap_err2string);
  DYNA_GET_FUNCTION(int (*)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long), ldap_entry2text);
  DYNA_GET_FUNCTION(int (*)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long, char *, char *), ldap_entry2html);
  
  server = ldap_open(conn->hostname, conn->port);
  if (server == NULL) {
    failf(data, "LDAP: Cannot connect to %s:%d",
	  conn->hostname, conn->port);
    status = CURLE_COULDNT_CONNECT;
  } else {
    rc = ldap_simple_bind_s(server,
                            conn->bits.user_passwd?data->state.user:NULL,
                            conn->bits.user_passwd?data->state.passwd:NULL);
    if (rc != 0) {
      failf(data, "LDAP: %s", ldap_err2string(rc));
      status = CURLE_LDAP_CANNOT_BIND;
    } else {
      rc = ldap_url_search_s(server, data->change.url, 0, &result);
      if (rc != 0) {
	failf(data, "LDAP: %s", ldap_err2string(rc));
	status = CURLE_LDAP_SEARCH_FAILED;
      } else {
	for (entryIterator = ldap_first_entry(server, result);
	     entryIterator;
	     entryIterator = ldap_next_entry(server, entryIterator))
	  {
	    if (ldaptext) {
	      rc = ldap_entry2text(server, NULL, entryIterator, NULL,
				   NULL, NULL, WriteProc, data,
				   (char *)"", 0, 0);
	      if (rc != 0) {
		failf(data, "LDAP: %s", ldap_err2string(rc));
		status = CURLE_LDAP_SEARCH_FAILED;
	      }
	    } else {
	      rc = ldap_entry2html(server, NULL, entryIterator, NULL,
				   NULL, NULL, WriteProc, data,
				   (char *)"", 0, 0, NULL, NULL);
	      if (rc != 0) {
		failf(data, "LDAP: %s", ldap_err2string(rc));
		status = CURLE_LDAP_SEARCH_FAILED;
	      }
	    }
	  }
      }
      ldap_unbind_s(server);
    }
  }
  DynaClose();

  /* no data to transfer */
  Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
  
  return status;
}
示例#4
0
CURLcode Curl_ldap(struct connectdata *conn)
{
  CURLcode status = CURLE_OK;
  int rc;
  void *(*ldap_init)(char *, int);
  int (*ldap_simple_bind_s)(void *, char *, char *);
  int (*ldap_unbind_s)(void *);
  int (*ldap_url_parse)(char *, LDAPURLDesc **);
  void (*ldap_free_urldesc)(void *);
  int (*ldap_search_s)(void *, char *, int, char *, char **, int, void **);
  int (*ldap_search_st)(void *, char *, int, char *, char **, int, void *, void **);
  void *(*ldap_first_entry)(void *, void *);
  void *(*ldap_next_entry)(void *, void *);
  char *(*ldap_err2string)(int);
  char *(*ldap_get_dn)(void *, void *);
  char *(*ldap_first_attribute)(void *, void *, void **);
  char *(*ldap_next_attribute)(void *, void *, void *);
  char **(*ldap_get_values)(void *, void *, char *);
  void (*ldap_value_free)(char **);
  void (*ldap_memfree)(void *);
  void (*ber_free)(void *, int);
 
  void *server;
  LDAPURLDesc *ludp;
  void *result;
  void *entryIterator;
  void *ber;
  void *attribute;

  struct SessionHandle *data=conn->data;
  
  infof(data, "LDAP: %s\n", data->change.url);

  DynaOpen();
  if (libldap == NULL) {
    failf(data, "The needed LDAP library/libraries couldn't be opened");
    return CURLE_LIBRARY_NOT_FOUND;
  }

  /* The types are needed because ANSI C distinguishes between
   * pointer-to-object (data) and pointer-to-function.
   */
  DYNA_GET_FUNCTION(void *(*)(char *, int), ldap_init);
  DYNA_GET_FUNCTION(int (*)(void *, char *, char *), ldap_simple_bind_s);
  DYNA_GET_FUNCTION(int (*)(void *), ldap_unbind_s);
  DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse);
  DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc);
  DYNA_GET_FUNCTION(int (*)(void *, char *, int, char *, char **, int, void **), ldap_search_s);
  DYNA_GET_FUNCTION(int (*)(void *, char *, int, char *, char **, int, void *, void **), ldap_search_st);
  DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_first_entry);
  DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_next_entry);
  DYNA_GET_FUNCTION(char *(*)(int), ldap_err2string);
  DYNA_GET_FUNCTION(char *(*)(void *, void *), ldap_get_dn);
  DYNA_GET_FUNCTION(char *(*)(void *, void *, void **), ldap_first_attribute);
  DYNA_GET_FUNCTION(char *(*)(void *, void *, void *), ldap_next_attribute);
  DYNA_GET_FUNCTION(char **(*)(void *, void *, char *), ldap_get_values);
  DYNA_GET_FUNCTION(void (*)(char **), ldap_value_free);
  DYNA_GET_FUNCTION(void (*)(void *), ldap_memfree);
  DYNA_GET_FUNCTION(void (*)(void *, int), ber_free);
  
  server = ldap_init(conn->hostname, conn->port);
  if (server == NULL) {
    failf(data, "LDAP: Cannot connect to %s:%d",
	  conn->hostname, conn->port);
    status = CURLE_COULDNT_CONNECT;
  }
  else {
    rc = ldap_simple_bind_s(server,
                            conn->bits.user_passwd?conn->user:NULL,
                            conn->bits.user_passwd?conn->passwd:NULL);
    if (rc != 0) {
      failf(data, "LDAP: %s", ldap_err2string(rc));
      status = CURLE_LDAP_CANNOT_BIND;
    }
    else {
      rc = ldap_url_parse(data->change.url, &ludp);
      if (rc != 0) {
	failf(data, "LDAP: %s", ldap_err2string(rc));
	status = CURLE_LDAP_INVALID_URL;
      }
      else {
	rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
                           ludp->lud_filter, ludp->lud_attrs, 0, &result);
	if (rc != 0) {
	  failf(data, "LDAP: %s", ldap_err2string(rc));
	  status = CURLE_LDAP_SEARCH_FAILED;
	}
	else {
	  for (entryIterator = ldap_first_entry(server, result);
	       entryIterator;
	       entryIterator = ldap_next_entry(server, entryIterator)) {
            char *dn = ldap_get_dn(server, entryIterator);
            char **vals;
            int i;
            
            Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
            Curl_client_write(data, CLIENTWRITE_BODY, dn, 0);
            Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
            for(attribute = ldap_first_attribute(server, entryIterator,
                                                 &ber); 
                attribute; 
                attribute = ldap_next_attribute(server, entryIterator,
                                                ber) ) {
              vals = ldap_get_values(server, entryIterator, attribute);
              if (vals != NULL) {
                for(i = 0; (vals[i] != NULL); i++) {
                  Curl_client_write(data, CLIENTWRITE_BODY, (char*)"\t", 1);
                  Curl_client_write(data, CLIENTWRITE_BODY, attribute, 0);
                  Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
                  Curl_client_write(data, CLIENTWRITE_BODY, vals[i], 0);
                  Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
                }
              }

              /* Free memory used to store values */
              ldap_value_free(vals);
            }
            Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
            
            ldap_memfree(attribute);
            ldap_memfree(dn);
            if (ber) ber_free(ber, 0);
          }
	}

	ldap_free_urldesc(ludp);
      }
      ldap_unbind_s(server);
    }
  }
  DynaClose();

  /* no data to transfer */
  Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
  
  return status;
}
示例#5
0
CURLcode Curl_http(struct connectdata *conn)
{
  struct SessionHandle *data=conn->data;
  char *buf = data->state.buffer; /* this is a short cut to the buffer */
  CURLcode result=CURLE_OK;
  struct HTTP *http;
  struct Cookie *co=NULL; /* no cookies from start */
  char *ppath = conn->ppath; /* three previous function arguments */
  char *host = conn->name;
  long *bytecount = &conn->bytecount;

  if(!conn->proto.http) {
    /* Only allocate this struct if we don't already have it! */

    http = (struct HTTP *)malloc(sizeof(struct HTTP));
    if(!http)
      return CURLE_OUT_OF_MEMORY;
    memset(http, 0, sizeof(struct HTTP));
    conn->proto.http = http;
  }
  else
    http = conn->proto.http;

  /* We default to persistant connections */
  conn->bits.close = FALSE;

  if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
       data->set.upload) {
    data->set.httpreq = HTTPREQ_PUT;
  }
  
  /* The User-Agent string has been built in url.c already, because it might
     have been used in the proxy connect, but if we have got a header with
     the user-agent string specified, we erase the previously made string
     here. */
  if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
    free(conn->allocptr.uagent);
    conn->allocptr.uagent=NULL;
  }

  if((conn->bits.user_passwd) && !checkheaders(data, "Authorization:")) {
    char *authorization;

    /* To prevent the user+password to get sent to other than the original
       host due to a location-follow, we do some weirdo checks here */
    if(!data->state.this_is_a_follow ||
       !data->state.auth_host ||
       strequal(data->state.auth_host, conn->hostname)) {
      sprintf(data->state.buffer, "%s:%s",
              data->state.user, data->state.passwd);
      if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
                            &authorization) >= 0) {
        if(conn->allocptr.userpwd)
          free(conn->allocptr.userpwd);
        conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012",
                                          authorization);
        free(authorization);
      }
    }
  }
  if((data->change.referer) && !checkheaders(data, "Referer:")) {
    if(conn->allocptr.ref)
      free(conn->allocptr.ref);
    conn->allocptr.ref = aprintf("Referer: %s\015\012", data->change.referer);
  }
  if(data->set.cookie && !checkheaders(data, "Cookie:")) {
    if(conn->allocptr.cookie)
      free(conn->allocptr.cookie);
    conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie);
  }

  if(data->cookies) {
    co = Curl_cookie_getlist(data->cookies,
                             host, ppath,
                             conn->protocol&PROT_HTTPS?TRUE:FALSE);
  }
  if (data->change.proxy &&
      !data->set.tunnel_thru_httpproxy &&
      !(conn->protocol&PROT_HTTPS))  {
    /* The path sent to the proxy is in fact the entire URL */
    ppath = data->change.url;
  }
  if(HTTPREQ_POST_FORM == data->set.httpreq) {
    /* we must build the whole darned post sequence first, so that we have
       a size of the whole shebang before we start to send it */
    http->sendit = Curl_getFormData(data->set.httppost, &http->postsize);
  }

  if(!checkheaders(data, "Host:")) {
    /* if ptr_host is already set, it is almost OK since we only re-use
       connections to the very same host and port, but when we use a HTTP
       proxy we have a persistant connect and yet we must change the Host:
       header! */

    if(conn->allocptr.host)
      free(conn->allocptr.host);

    if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
       (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
      /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
         the port number in the host string */
      conn->allocptr.host = aprintf("Host: %s\r\n", host);
    else
      conn->allocptr.host = aprintf("Host: %s:%d\r\n", host,
                                    conn->remote_port);
  }

  if(!checkheaders(data, "Pragma:"))
    http->p_pragma = "Pragma: no-cache\r\n";

  if(!checkheaders(data, "Accept:"))
    http->p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n";

  if(( (HTTPREQ_POST == data->set.httpreq) ||
       (HTTPREQ_POST_FORM == data->set.httpreq) ||
       (HTTPREQ_PUT == data->set.httpreq) ) &&
     conn->resume_from) {
    /**********************************************************************
     * Resuming upload in HTTP means that we PUT or POST and that we have
     * got a resume_from value set. The resume value has already created
     * a Range: header that will be passed along. We need to "fast forward"
     * the file the given number of bytes and decrease the assume upload
     * file size before we continue this venture in the dark lands of HTTP.
     *********************************************************************/
   
    if(conn->resume_from < 0 ) {
      /*
       * This is meant to get the size of the present remote-file by itself.
       * We don't support this now. Bail out!
       */
       conn->resume_from = 0;
    }

    if(conn->resume_from) {
      /* do we still game? */
      int passed=0;

      /* Now, let's read off the proper amount of bytes from the
         input. If we knew it was a proper file we could've just
         fseek()ed but we only have a stream here */
      do {
        int readthisamountnow = (conn->resume_from - passed);
        int actuallyread;

        if(readthisamountnow > BUFSIZE)
          readthisamountnow = BUFSIZE;

        actuallyread =
          data->set.fread(data->state.buffer, 1, readthisamountnow,
                          data->set.in);

        passed += actuallyread;
        if(actuallyread != readthisamountnow) {
          failf(data, "Could only read %d bytes from the input",
                passed);
          return CURLE_READ_ERROR;
        }
      } while(passed != conn->resume_from); /* loop until done */

      /* now, decrease the size of the read */
      if(data->set.infilesize>0) {
        data->set.infilesize -= conn->resume_from;

        if(data->set.infilesize <= 0) {
          failf(data, "File already completely uploaded");
          return CURLE_PARTIAL_FILE;
        }
      }
      /* we've passed, proceed as normal */
    }
  }
  if(conn->bits.use_range) {
    /*
     * A range is selected. We use different headers whether we're downloading
     * or uploading and we always let customized headers override our internal
     * ones if any such are specified.
     */
    if((data->set.httpreq == HTTPREQ_GET) &&
       !checkheaders(data, "Range:")) {
      conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", conn->range);
    }
    else if((data->set.httpreq != HTTPREQ_GET) &&
            !checkheaders(data, "Content-Range:")) {

      if(conn->resume_from) {
        /* This is because "resume" was selected */
        long total_expected_size= conn->resume_from + data->set.infilesize;
        conn->allocptr.rangeline = aprintf("Content-Range: bytes %s%ld/%ld\r\n",
                                      conn->range, total_expected_size-1,
                                      total_expected_size);
      }
      else {
        /* Range was selected and then we just pass the incoming range and 
           append total size */
        conn->allocptr.rangeline = aprintf("Content-Range: bytes %s/%d\r\n",
                                      conn->range, data->set.infilesize);
      }
    }
  }

  do {
    /* Use 1.1 unless the use specificly asked for 1.0 */
    const char *httpstring=
      data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";

    send_buffer *req_buffer;
    struct curl_slist *headers=data->set.headers;

    /* initialize a dynamic send-buffer */
    req_buffer = add_buffer_init();

    /* add the main request stuff */
    add_bufferf(req_buffer,
                "%s " /* GET/HEAD/POST/PUT */
                "%s HTTP/%s\r\n" /* path */
                "%s" /* proxyuserpwd */
                "%s" /* userpwd */
                "%s" /* range */
                "%s" /* user agent */
                "%s" /* cookie */
                "%s" /* host */
                "%s" /* pragma */
                "%s" /* accept */
                "%s", /* referer */

                data->set.customrequest?data->set.customrequest:
                (data->set.no_body?"HEAD":
                 ((HTTPREQ_POST == data->set.httpreq) ||
                  (HTTPREQ_POST_FORM == data->set.httpreq))?"POST":
                 (HTTPREQ_PUT == data->set.httpreq)?"PUT":"GET"),
                ppath, httpstring,
                (conn->bits.proxy_user_passwd &&
                 conn->allocptr.proxyuserpwd)?conn->allocptr.proxyuserpwd:"",
                (conn->bits.user_passwd && conn->allocptr.userpwd)?
                conn->allocptr.userpwd:"",
                (conn->bits.use_range && conn->allocptr.rangeline)?
                conn->allocptr.rangeline:"",
                (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
                conn->allocptr.uagent:"",
                (conn->allocptr.cookie?conn->allocptr.cookie:""), /* Cookie: <data> */
                (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
                http->p_pragma?http->p_pragma:"",
                http->p_accept?http->p_accept:"",
                (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> <CRLF> */
                );

    if(co) {
      int count=0;
      struct Cookie *store=co;
      /* now loop through all cookies that matched */
      while(co) {
        if(co->value && strlen(co->value)) {
          if(0 == count) {
            add_bufferf(req_buffer, "Cookie: ");
          }
          add_bufferf(req_buffer,
                      "%s%s=%s", count?"; ":"", co->name, co->value);
          count++;
        }
        co = co->next; /* next cookie please */
      }
      if(count) {
        add_buffer(req_buffer, "\r\n", 2);
      }
      Curl_cookie_freelist(store); /* free the cookie list */
      co=NULL;
    }

    if(data->set.timecondition) {
      struct tm *thistime;

      /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
       * header family should have their times set in GMT as RFC2616 defines:
       * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
       * (GMT), without exception. For the purposes of HTTP, GMT is exactly
       * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
       */

#ifdef HAVE_GMTIME_R
      /* thread-safe version */
      struct tm keeptime;
      thistime = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
#else
      thistime = gmtime(&data->set.timevalue);
#endif
      if(NULL == thistime) {
        failf(data, "localtime() failed!");
        return CURLE_OUT_OF_MEMORY;
      }

#ifdef HAVE_STRFTIME
      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
      strftime(buf, BUFSIZE-1, "%a, %d %b %Y %H:%M:%S GMT", thistime);
#else
      /* TODO: Right, we *could* write a replacement here */
      strcpy(buf, "no strftime() support");
#endif
      switch(data->set.timecondition) {
      case TIMECOND_IFMODSINCE:
      default:
        add_bufferf(req_buffer,
                    "If-Modified-Since: %s\r\n", buf);
        break;
      case TIMECOND_IFUNMODSINCE:
        add_bufferf(req_buffer,
                    "If-Unmodified-Since: %s\r\n", buf);
        break;
      case TIMECOND_LASTMOD:
        add_bufferf(req_buffer,
                    "Last-Modified: %s\r\n", buf);
        break;
      }
    }

    while(headers) {
      char *ptr = strchr(headers->data, ':');
      if(ptr) {
        /* we require a colon for this to be a true header */

        ptr++; /* pass the colon */
        while(*ptr && isspace((int)*ptr))
          ptr++;

        if(*ptr) {
          /* only send this if the contents was non-blank */

          add_bufferf(req_buffer, "%s\r\n", headers->data);
        }
      }
      headers = headers->next;
    }

    if(HTTPREQ_POST_FORM == data->set.httpreq) {
      if(Curl_FormInit(&http->form, http->sendit)) {
        failf(data, "Internal HTTP POST error!");
        return CURLE_HTTP_POST_ERROR;
      }

      http->storefread = data->set.fread; /* backup */
      http->in = data->set.in; /* backup */
          
      data->set.fread = (curl_read_callback)
        Curl_FormReader; /* set the read function to read from the
                            generated form data */
      data->set.in = (FILE *)&http->form;

      add_bufferf(req_buffer,
                  "Content-Length: %d\r\n", http->postsize);

      if(!checkheaders(data, "Expect:")) {
        /* if not disabled explicitly we add a Expect: 100-continue
           to the headers which actually speeds up post operations (as
           there is one packet coming back from the web server) */
        add_bufferf(req_buffer,
                    "Expect: 100-continue\r\n");
        data->set.expect100header = TRUE;
      }

      if(!checkheaders(data, "Content-Type:")) {
        /* Get Content-Type: line from Curl_FormReadOneLine, which happens
           to always be the first line. We can know this for sure since
           we always build the formpost linked list the same way!

           The Content-Type header line also contains the MIME boundary
           string etc why disabling this header is likely to not make things
           work, but we support it anyway.
        */
        char contentType[256];
        int linelength=0;
        linelength = Curl_FormReadOneLine (contentType,
                                           sizeof(contentType),
                                           1,
                                           (FILE *)&http->form);
        if(linelength == -1) {
          failf(data, "Could not get Content-Type header line!");
          return CURLE_HTTP_POST_ERROR;
        }
        add_buffer(req_buffer, contentType, linelength);
      }

      /* make the request end in a true CRLF */
      add_buffer(req_buffer, "\r\n", 2);

      /* set upload size to the progress meter */
      Curl_pgrsSetUploadSize(data, http->postsize);

      /* fire away the whole request to the server */
      result = add_buffer_send(conn->firstsocket, conn, req_buffer,
                               &data->info.request_size);
      if(result)
        failf(data, "Failed sending POST request");
      else
        /* setup variables for the upcoming transfer */
        result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
                               &http->readbytecount,
                               conn->firstsocket,
                               &http->writebytecount);
      if(result) {
        Curl_formclean(http->sendit); /* free that whole lot */
        return result;
      }
    }
    else if(HTTPREQ_PUT == data->set.httpreq) {
      /* Let's PUT the data to the server! */

      if(data->set.infilesize>0) {
        add_bufferf(req_buffer,
                    "Content-Length: %d\r\n\r\n", /* file size */
                    data->set.infilesize );
      }
      else
        add_bufferf(req_buffer, "\015\012");

      /* set the upload size to the progress meter */
      Curl_pgrsSetUploadSize(data, data->set.infilesize);

      /* this sends the buffer and frees all the buffer resources */
      result = add_buffer_send(conn->firstsocket, conn, req_buffer,
                               &data->info.request_size);
      if(result)
        failf(data, "Faied sending POST request");
      else
        /* prepare for transfer */
        result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
                               &http->readbytecount,
                               conn->firstsocket,
                               &http->writebytecount);
      if(result)
        return result;
      
    }
    else {
      if(HTTPREQ_POST == data->set.httpreq) {
        /* this is the simple POST, using x-www-form-urlencoded style */

        if(!data->set.postfields) {
          /*
           * This is an attempt to do a POST without having anything to
           * actually send. Let's make a NULL pointer equal "" here. Good/bad
           * ?
           */
          data->set.postfields = (char *)"";
          data->set.postfieldsize = 0; /* it might been set to something illegal,
                                      anything > 0 would be! */
        }

        if(!checkheaders(data, "Content-Length:"))
          /* we allow replacing this header, although it isn't very wise to
             actually set your own */
          add_bufferf(req_buffer,
                      "Content-Length: %d\r\n",
                      (data->set.postfieldsize?data->set.postfieldsize:
                       strlen(data->set.postfields)) );

        if(!checkheaders(data, "Content-Type:"))
          add_bufferf(req_buffer,
                      "Content-Type: application/x-www-form-urlencoded\r\n");

        /* and here comes the actual data */
        if(data->set.postfieldsize) {
          add_buffer(req_buffer, "\r\n", 2);
          add_buffer(req_buffer, data->set.postfields,
                     data->set.postfieldsize);
        }
        else {
          add_bufferf(req_buffer,
                      "\r\n"
                      "%s",
                      data->set.postfields );
        }
      }
      else
        add_buffer(req_buffer, "\r\n", 2);

      /* issue the request */
      result = add_buffer_send(conn->firstsocket, conn, req_buffer,
                               &data->info.request_size);

      if(result)
        failf(data, "Failed sending HTTP request");
      else
        /* HTTP GET/HEAD download: */
        result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, bytecount,
                               -1, NULL); /* nothing to upload */
    }
    if(result)
      return result;
  } while (0); /* this is just a left-over from the multiple document download
                  attempts */

  return CURLE_OK;
}