New Curl version 7.10.3

This commit is contained in:
Andy Cedilnik 2003-01-14 09:12:37 -05:00
parent 6c61762b0f
commit 587b067880
27 changed files with 1622 additions and 1193 deletions

View File

@ -2,7 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 1.5)
PROJECT(LIBCURL C) PROJECT(LIBCURL C)
SET(PACKAGE "curl") SET(PACKAGE "curl")
SET(VERSION "7.10.2") SET(VERSION "7.10.3")
SET(PACKAGE_TARNAME " ") SET(PACKAGE_TARNAME " ")
SET(OPERATING_SYSTEM ${CMAKE_SYSTEM_NAME}) SET(OPERATING_SYSTEM ${CMAKE_SYSTEM_NAME})

View File

@ -61,6 +61,8 @@ static void decodeQuantum(unsigned char *dest, char *src)
x = (x << 6) + 62; x = (x << 6) + 62;
else if(src[i] == '/') else if(src[i] == '/')
x = (x << 6) + 63; x = (x << 6) + 63;
else if(src[i] == '=')
x = (x << 6);
} }
dest[2] = (unsigned char)(x & 255); x >>= 8; dest[2] = (unsigned char)(x & 255); x >>= 8;
@ -78,6 +80,7 @@ static void base64Decode(unsigned char *dest, char *src, int *rawLength)
int length = 0; int length = 0;
int equalsTerm = 0; int equalsTerm = 0;
int i; int i;
int numQuantums;
unsigned char lastQuantum[3]; unsigned char lastQuantum[3];
while((src[length] != '=') && src[length]) while((src[length] != '=') && src[length])
@ -85,16 +88,18 @@ static void base64Decode(unsigned char *dest, char *src, int *rawLength)
while(src[length+equalsTerm] == '=') while(src[length+equalsTerm] == '=')
equalsTerm++; equalsTerm++;
numQuantums = (length + equalsTerm) / 4;
if(rawLength) if(rawLength)
*rawLength = (length * 3 / 4) - equalsTerm; *rawLength = (numQuantums * 3) - equalsTerm;
for(i = 0; i < length/4 - 1; i++) { for(i = 0; i < numQuantums - 1; i++) {
decodeQuantum(dest, src); decodeQuantum(dest, src);
dest += 3; src += 4; dest += 3; src += 4;
} }
decodeQuantum(lastQuantum, src); decodeQuantum(lastQuantum, src);
for(i = 0; i < 3 - equalsTerm; i++) dest[i] = lastQuantum[i]; for(i = 0; i < 3 - equalsTerm; i++)
dest[i] = lastQuantum[i];
} }
@ -194,20 +199,21 @@ int Curl_base64_decode(const char *str, void *data)
#define TEST_NEED_SUCK #define TEST_NEED_SUCK
void *suck(int *); void *suck(int *);
int main(int argc, char **argv, char **envp) { int main(int argc, char **argv, char **envp)
char *base64; {
int base64Len; char *base64;
unsigned char *data; int base64Len;
int dataLen; unsigned char *data;
int dataLen;
data = (unsigned char *)suck(&dataLen); data = (unsigned char *)suck(&dataLen);
base64Len = Curl_base64_encode(data, dataLen, &base64); base64Len = Curl_base64_encode(data, dataLen, &base64);
fprintf(stderr, "%d\n", base64Len); fprintf(stderr, "%d\n", base64Len);
fprintf(stdout, "%s", base64); fprintf(stdout, "%s", base64);
free(base64); free(data); free(base64); free(data);
return 0; return 0;
} }
#endif #endif
@ -220,47 +226,47 @@ int main(int argc, char **argv, char **envp) {
#define TEST_NEED_SUCK #define TEST_NEED_SUCK
void *suck(int *); void *suck(int *);
int main(int argc, char **argv, char **envp) { int main(int argc, char **argv, char **envp)
char *base64; {
int base64Len; char *base64;
unsigned char *data; int base64Len;
int dataLen; unsigned char *data;
int dataLen;
base64 = (char *)suck(&base64Len); base64 = (char *)suck(&base64Len);
data = (unsigned char *)malloc(base64Len * 3/4 + 8); data = (unsigned char *)malloc(base64Len * 3/4 + 8);
dataLen = Curl_base64_decode(base64, data); dataLen = Curl_base64_decode(base64, data);
fprintf(stderr, "%d\n", dataLen); fprintf(stderr, "%d\n", dataLen);
fwrite(data,1,dataLen,stdout); fwrite(data,1,dataLen,stdout);
free(base64); free(data);
free(base64); free(data); return 0;
return 0;
} }
#endif #endif
#ifdef TEST_NEED_SUCK #ifdef TEST_NEED_SUCK
/* this function 'sucks' in as much as possible from stdin */ /* this function 'sucks' in as much as possible from stdin */
void *suck(int *lenptr) { void *suck(int *lenptr)
int cursize = 8192; {
unsigned char *buf = NULL; int cursize = 8192;
int lastread; unsigned char *buf = NULL;
int len = 0; int lastread;
int len = 0;
do { do {
cursize *= 2; cursize *= 2;
buf = (unsigned char *)realloc(buf, cursize); buf = (unsigned char *)realloc(buf, cursize);
memset(buf + len, 0, cursize - len); memset(buf + len, 0, cursize - len);
lastread = fread(buf + len, 1, cursize - len, stdin); lastread = fread(buf + len, 1, cursize - len, stdin);
len += lastread; len += lastread;
} while(!feof(stdin)); } while(!feof(stdin));
lenptr[0] = len; lenptr[0] = len;
return (void *)buf; return (void *)buf;
} }
#endif #endif
/* /*
* local variables: * local variables:
* eval: (load-file "../curl-mode.el") * eval: (load-file "../curl-mode.el")

View File

@ -176,10 +176,9 @@ int waitconnect(int sockfd, /* socket */
/* timeout, no connect today */ /* timeout, no connect today */
return 1; return 1;
if(FD_ISSET(sockfd, &errfd)) { if(FD_ISSET(sockfd, &errfd))
/* error condition caught */ /* error condition caught */
return 2; return 2;
}
/* we have a connect! */ /* we have a connect! */
return 0; return 0;
@ -380,6 +379,11 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return CURLE_OPERATION_TIMEOUTED; return CURLE_OPERATION_TIMEOUTED;
} }
} }
if(conn->bits.tcpconnect) {
/* we are connected already! */
*connected = TRUE;
return CURLE_OK;
}
/* check for connect without timeout as we want to return immediately */ /* check for connect without timeout as we want to return immediately */
rc = waitconnect(sockfd, 0); rc = waitconnect(sockfd, 0);
@ -646,6 +650,15 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
} }
} }
/* The '1 == rc' comes from the waitconnect(), and not from connect().
We can be sure of this since connect() cannot return 1. */
if((1 == rc) && (data->state.used_interface == Curl_if_multi)) {
/* Timeout when running the multi interface, we return here with a
CURLE_OK return code. */
rc = 0;
break;
}
if(0 == rc) { if(0 == rc) {
int err = socketerror(sockfd); int err = socketerror(sockfd);
if ((0 == err) || (EISCONN == err)) { if ((0 == err) || (EISCONN == err)) {
@ -658,12 +671,6 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
} }
if(0 != rc) { if(0 != rc) {
if(data->state.used_interface == Curl_if_multi) {
/* When running the multi interface, we bail out here */
rc = 0;
break;
}
/* get a new timeout for next attempt */ /* get a new timeout for next attempt */
after = Curl_tvnow(); after = Curl_tvnow();
timeout_ms -= Curl_tvdiff(after, before); timeout_ms -= Curl_tvdiff(after, before);

View File

@ -66,9 +66,9 @@ struct curl_httppost {
char *contents; /* pointer to allocated data contents */ char *contents; /* pointer to allocated data contents */
long contentslength; /* length of contents field */ long contentslength; /* length of contents field */
/* CMC: Added support for buffer uploads */ /* CMC: Added support for buffer uploads */
char *buffer; /* pointer to allocated buffer contents */ char *buffer; /* pointer to allocated buffer contents */
long bufferlength; /* length of buffer field */ long bufferlength; /* length of buffer field */
char *contenttype; /* Content-Type */ char *contenttype; /* Content-Type */
struct curl_slist* contentheader; /* list of extra headers for this form */ struct curl_slist* contentheader; /* list of extra headers for this form */
@ -96,7 +96,9 @@ typedef int (*curl_progress_callback)(void *clientp,
double ultotal, double ultotal,
double ulnow); double ulnow);
#define CURL_MAX_WRITE_SIZE 20480 /* Tests have proven that 20K is a very bad buffer size for uploads on
Windows, while 16K for some odd reason performed a lot better. */
#define CURL_MAX_WRITE_SIZE 16384
typedef size_t (*curl_write_callback)(char *buffer, typedef size_t (*curl_write_callback)(char *buffer,
size_t size, size_t size,
@ -160,7 +162,7 @@ typedef enum {
CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ CURLE_FTP_COULDNT_RETR_FILE, /* 19 */
CURLE_FTP_WRITE_ERROR, /* 20 */ CURLE_FTP_WRITE_ERROR, /* 20 */
CURLE_FTP_QUOTE_ERROR, /* 21 */ CURLE_FTP_QUOTE_ERROR, /* 21 */
CURLE_HTTP_NOT_FOUND, /* 22 */ CURLE_HTTP_RETURNED_ERROR, /* 22 */
CURLE_WRITE_ERROR, /* 23 */ CURLE_WRITE_ERROR, /* 23 */
CURLE_MALFORMAT_USER, /* 24 - user name is illegally specified */ CURLE_MALFORMAT_USER, /* 24 - user name is illegally specified */
CURLE_FTP_COULDNT_STOR_FILE, /* 25 - failed FTP upload */ CURLE_FTP_COULDNT_STOR_FILE, /* 25 - failed FTP upload */
@ -207,6 +209,7 @@ typedef enum {
/* Make a spelling correction for the operation timed-out define */ /* Make a spelling correction for the operation timed-out define */
#define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED #define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED
#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
typedef enum { typedef enum {
CURLPROXY_HTTP = 0, CURLPROXY_HTTP = 0,
@ -610,6 +613,11 @@ typedef enum {
the response to be compressed. */ the response to be compressed. */
CINIT(ENCODING, OBJECTPOINT, 102), CINIT(ENCODING, OBJECTPOINT, 102),
/* Set pointer to private data */
CINIT(PRIVATE, OBJECTPOINT, 103),
/* Set aliases for HTTP 200 in the HTTP Response header */
CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
CURLOPT_LASTENTRY /* the last unused */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;
@ -803,8 +811,8 @@ CURLcode curl_global_init(long flags);
void curl_global_cleanup(void); void curl_global_cleanup(void);
/* This is the version number */ /* This is the version number */
#define LIBCURL_VERSION "7.10.2" #define LIBCURL_VERSION "7.10.3"
#define LIBCURL_VERSION_NUM 0x070a02 #define LIBCURL_VERSION_NUM 0x070a03
/* linked-list structure for the CURLOPT_QUOTE option (and other) */ /* linked-list structure for the CURLOPT_QUOTE option (and other) */
struct curl_slist { struct curl_slist {
@ -861,16 +869,13 @@ typedef enum {
CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19,
CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20,
CURLINFO_PRIVATE = CURLINFO_STRING + 21,
/* Fill in new entries here! */ /* Fill in new entries here! */
CURLINFO_LASTONE = 21 CURLINFO_LASTONE = 22
} CURLINFO; } CURLINFO;
/* unfortunately, the easy.h and multi.h include files need options and info
stuff before they can be included! */
#include "easy.h" /* nothing in curl is fun without the easy stuff */
#include "multi.h"
typedef enum { typedef enum {
CURLCLOSEPOLICY_NONE, /* first, never use this */ CURLCLOSEPOLICY_NONE, /* first, never use this */
@ -894,35 +899,56 @@ typedef enum {
* Setup defines, protos etc for the sharing stuff. * Setup defines, protos etc for the sharing stuff.
*/ */
/* Different types of locks that a share can aquire */ /* Different data locks for a single share */
typedef enum { typedef enum {
CURL_LOCK_TYPE_NONE = 0, CURL_LOCK_DATA_NONE = 0,
CURL_LOCK_TYPE_COOKIE = 1<<0, CURL_LOCK_DATA_COOKIE = 1,
CURL_LOCK_TYPE_DNS = 1<<1, CURL_LOCK_DATA_DNS = 2,
CURL_LOCK_TYPE_SSL_SESSION = 2<<1, CURL_LOCK_DATA_SSL_SESSION = 3,
CURL_LOCK_TYPE_CONNECT = 2<<2, CURL_LOCK_DATA_CONNECT = 4,
CURL_LOCK_TYPE_LAST CURL_LOCK_DATA_LAST
} curl_lock_type; } curl_lock_data;
typedef void (*curl_lock_function)(CURL *, curl_lock_type, void *); /* Different lock access types */
typedef void (*curl_unlock_function)(CURL *, curl_lock_type, void *); typedef enum {
CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */
CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
CURL_LOCK_ACCESS_LAST /* never use */
} curl_lock_access;
typedef struct { typedef void (*curl_lock_function)(CURL *handle,
unsigned int specifier; curl_lock_data data,
unsigned int locked; curl_lock_access access,
unsigned int dirty; void *userptr);
typedef void (*curl_unlock_function)(CURL *handle,
curl_lock_function lockfunc; curl_lock_data data,
curl_unlock_function unlockfunc; void *userptr);
void *clientdata;
} curl_share;
curl_share *curl_share_init (void); typedef void CURLSH;
CURLcode curl_share_setopt (curl_share *, curl_lock_type, int);
CURLcode curl_share_set_lock_function (curl_share *, curl_lock_function); typedef enum {
CURLcode curl_share_set_unlock_function (curl_share *, curl_unlock_function); CURLSHE_OK, /* all is fine */
CURLcode curl_share_set_lock_data (curl_share *, void *); CURLSHE_BAD_OPTION, /* 1 */
CURLcode curl_share_destroy (curl_share *); CURLSHE_IN_USE, /* 2 */
CURLSHE_INVALID, /* 3 */
CURLSHE_LAST /* never use */
} CURLSHcode;
typedef enum {
CURLSHOPT_NONE, /* don't use */
CURLSHOPT_SHARE, /* specify a data type to share */
CURLSHOPT_UNSHARE, /* specify shich data type to stop sharing */
CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */
CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock
callback functions */
CURLSHOPT_LAST /* never use */
} CURLSHoption;
CURLSH *curl_share_init(void);
CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
CURLSHcode curl_share_cleanup(CURLSH *);
/**************************************************************************** /****************************************************************************
* Structures for querying information about the curl library at runtime. * Structures for querying information about the curl library at runtime.
@ -965,4 +991,9 @@ curl_version_info_data *curl_version_info(CURLversion);
} }
#endif #endif
/* unfortunately, the easy.h and multi.h include files need options and info
stuff before they can be included! */
#include "easy.h" /* nothing in curl is fun without the easy stuff */
#include "multi.h"
#endif /* __CURL_CURL_H */ #endif /* __CURL_CURL_H */

View File

@ -233,15 +233,17 @@ CURLcode curl_easy_perform(CURL *curl)
{ {
struct SessionHandle *data = (struct SessionHandle *)curl; struct SessionHandle *data = (struct SessionHandle *)curl;
if (!data->hostcache) { if (Curl_global_host_cache_use(data) && data->hostcache != Curl_global_host_cache_get()) {
if (Curl_global_host_cache_use(data)) { if (data->hostcache) {
data->hostcache = Curl_global_host_cache_get(); Curl_hash_destroy(data->hostcache);
}
else {
data->hostcache = Curl_hash_alloc(7, Curl_freeaddrinfo);
} }
data->hostcache = Curl_global_host_cache_get();
} }
if (!data->hostcache) {
data->hostcache = Curl_hash_alloc(7, Curl_freednsinfo);
}
return Curl_perform(data); return Curl_perform(data);
} }

View File

@ -41,6 +41,7 @@ char *curl_escape(const char *string, int length)
{ {
int alloc = (length?length:(int)strlen(string))+1; int alloc = (length?length:(int)strlen(string))+1;
char *ns = malloc(alloc); char *ns = malloc(alloc);
char *testing_ptr = NULL;
unsigned char in; unsigned char in;
int newlen = alloc; int newlen = alloc;
int index=0; int index=0;
@ -55,9 +56,14 @@ char *curl_escape(const char *string, int length)
newlen += 2; /* the size grows with two, since this'll become a %XX */ newlen += 2; /* the size grows with two, since this'll become a %XX */
if(newlen > alloc) { if(newlen > alloc) {
alloc *= 2; alloc *= 2;
ns = realloc(ns, alloc); testing_ptr = realloc(ns, alloc);
if(!ns) if(!testing_ptr) {
free( ns );
return NULL; return NULL;
}
else {
ns = testing_ptr;
}
} }
sprintf(&ns[index], "%%%02X", in); sprintf(&ns[index], "%%%02X", in);
@ -80,6 +86,10 @@ char *curl_unescape(const char *string, int length)
unsigned char in; unsigned char in;
int index=0; int index=0;
unsigned int hex; unsigned int hex;
if( !ns ) {
return NULL;
}
while(--alloc > 0) { while(--alloc > 0) {
in = *string; in = *string;
@ -97,7 +107,6 @@ char *curl_unescape(const char *string, int length)
} }
ns[index]=0; /* terminate it */ ns[index]=0; /* terminate it */
return ns; return ns;
} }
void curl_free(void *p) void curl_free(void *p)

View File

@ -1319,7 +1319,7 @@ int Curl_FormReader(char *buffer,
wantedsize = size * nitems; wantedsize = size * nitems;
if(!form->data) if(!form->data)
return -1; /* nothing, error, empty */ return 0; /* nothing, error, empty */
do { do {

View File

@ -173,9 +173,9 @@ static CURLcode AllowServerConnect(struct SessionHandle *data,
* response and extract the relevant return code for the invoking function. * response and extract the relevant return code for the invoking function.
*/ */
int Curl_GetFTPResponse(char *buf, CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
struct connectdata *conn, struct connectdata *conn,
int *ftpcode) int *ftpcode) /* return the ftp-code */
{ {
/* Brand new implementation. /* Brand new implementation.
* We cannot read just one byte per read() and then go back to select() * We cannot read just one byte per read() and then go back to select()
@ -185,28 +185,21 @@ int Curl_GetFTPResponse(char *buf,
* line in a response or continue reading. */ * line in a response or continue reading. */
int sockfd = conn->firstsocket; int sockfd = conn->firstsocket;
int nread; /* total size read */
int perline; /* count bytes per line */ int perline; /* count bytes per line */
bool keepon=TRUE; bool keepon=TRUE;
ssize_t gotbytes; ssize_t gotbytes;
char *ptr; char *ptr;
int timeout = 3600; /* default timeout in seconds */ int timeout; /* timeout in seconds */
struct timeval interval; struct timeval interval;
fd_set rkeepfd; fd_set rkeepfd;
fd_set readfd; fd_set readfd;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
char *line_start; char *line_start;
int code=0; /* default "error code" to return */ int code=0; /* default ftp "error code" to return */
char *buf = data->state.buffer;
#define SELECT_OK 0 CURLcode result = CURLE_OK;
#define SELECT_ERROR 1 /* select() problems */
#define SELECT_TIMEOUT 2 /* took too long */
#define SELECT_MEMORY 3 /* no available memory */
#define SELECT_CALLBACK 4 /* aborted by callback */
int error = SELECT_OK;
struct FTP *ftp = conn->proto.ftp; struct FTP *ftp = conn->proto.ftp;
struct timeval now = Curl_tvnow();
if (ftpcode) if (ftpcode)
*ftpcode = 0; /* 0 for errors */ *ftpcode = 0; /* 0 for errors */
@ -221,20 +214,25 @@ int Curl_GetFTPResponse(char *buf,
ptr=buf; ptr=buf;
line_start = buf; line_start = buf;
nread=0; *nreadp=0;
perline=0; perline=0;
keepon=TRUE; keepon=TRUE;
while((nread<BUFSIZE) && (keepon && !error)) { while((*nreadp<BUFSIZE) && (keepon && !result)) {
/* check and reset timeout value every lap */ /* check and reset timeout value every lap */
if(data->set.timeout) { if(data->set.timeout)
/* if timeout is requested, find out how much remaining time we have */ /* if timeout is requested, find out how much remaining time we have */
timeout = data->set.timeout - /* timeout time */ timeout = data->set.timeout - /* timeout time */
Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */ Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
if(timeout <=0 ) { else
failf(data, "Transfer aborted due to timeout"); /* Even without a requested timeout, we only wait response_time
return -SELECT_TIMEOUT; /* already too little time */ seconds for the full response to arrive before we bail out */
} timeout = ftp->response_time -
Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
if(timeout <=0 ) {
failf(data, "Transfer aborted due to timeout");
return CURLE_OPERATION_TIMEDOUT; /* already too little time */
} }
if(!ftp->cache) { if(!ftp->cache) {
@ -244,19 +242,18 @@ int Curl_GetFTPResponse(char *buf,
switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) { switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
case -1: /* select() error, stop reading */ case -1: /* select() error, stop reading */
error = SELECT_ERROR; result = CURLE_RECV_ERROR;
failf(data, "Transfer aborted due to select() error"); failf(data, "Transfer aborted due to select() error: %d", errno);
break; break;
case 0: /* timeout */ case 0: /* timeout */
error = SELECT_TIMEOUT; result = CURLE_OPERATION_TIMEDOUT;
failf(data, "Transfer aborted due to timeout"); failf(data, "Transfer aborted due to timeout");
break; break;
default: default:
error = SELECT_OK;
break; break;
} }
} }
if(SELECT_OK == error) { if(CURLE_OK == result) {
/* /*
* This code previously didn't use the kerberos sec_read() code * This code previously didn't use the kerberos sec_read() code
* to read, but when we use Curl_read() it may do so. Do confirm * to read, but when we use Curl_read() it may do so. Do confirm
@ -272,8 +269,7 @@ int Curl_GetFTPResponse(char *buf,
ftp->cache_size = 0; /* zero the size just in case */ ftp->cache_size = 0; /* zero the size just in case */
} }
else { else {
int res = Curl_read(conn, sockfd, ptr, int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
BUFSIZE-nread, &gotbytes);
if(res < 0) if(res < 0)
/* EWOULDBLOCK */ /* EWOULDBLOCK */
continue; /* go looping again */ continue; /* go looping again */
@ -286,7 +282,7 @@ int Curl_GetFTPResponse(char *buf,
; ;
else if(gotbytes <= 0) { else if(gotbytes <= 0) {
keepon = FALSE; keepon = FALSE;
error = SELECT_ERROR; result = CURLE_RECV_ERROR;
failf(data, "Connection aborted"); failf(data, "Connection aborted");
} }
else { else {
@ -295,7 +291,7 @@ int Curl_GetFTPResponse(char *buf,
* line */ * line */
int i; int i;
nread += gotbytes; *nreadp += gotbytes;
for(i = 0; i < gotbytes; ptr++, i++) { for(i = 0; i < gotbytes; ptr++, i++) {
perline++; perline++;
if(*ptr=='\n') { if(*ptr=='\n') {
@ -315,7 +311,7 @@ int Curl_GetFTPResponse(char *buf,
result = Curl_client_write(data, CLIENTWRITE_HEADER, result = Curl_client_write(data, CLIENTWRITE_HEADER,
line_start, perline); line_start, perline);
if(result) if(result)
return -SELECT_CALLBACK; return result;
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \ #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
isdigit((int)line[2]) && (' ' == line[3])) isdigit((int)line[2]) && (' ' == line[3]))
@ -350,13 +346,13 @@ int Curl_GetFTPResponse(char *buf,
if(ftp->cache) if(ftp->cache)
memcpy(ftp->cache, line_start, ftp->cache_size); memcpy(ftp->cache, line_start, ftp->cache_size);
else else
return -SELECT_MEMORY; /**BANG**/ return CURLE_OUT_OF_MEMORY; /**BANG**/
} }
} /* there was data */ } /* there was data */
} /* if(no error) */ } /* if(no error) */
} /* while there's buffer left and loop is requested */ } /* while there's buffer left and loop is requested */
if(!error) if(!result)
code = atoi(buf); code = atoi(buf);
#ifdef KRB4 #ifdef KRB4
@ -378,13 +374,10 @@ int Curl_GetFTPResponse(char *buf,
} }
#endif #endif
if(error)
return -error;
if(ftpcode) if(ftpcode)
*ftpcode=code; /* return the initial number like this */ *ftpcode=code; /* return the initial number like this */
return nread; /* total amount of bytes read */ return result;
} }
/* /*
@ -417,6 +410,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
/* no need to duplicate them, the data struct won't change */ /* no need to duplicate them, the data struct won't change */
ftp->user = data->state.user; ftp->user = data->state.user;
ftp->passwd = data->state.passwd; ftp->passwd = data->state.passwd;
ftp->response_time = 3600; /* set default response time-out */
if (data->set.tunnel_thru_httpproxy) { if (data->set.tunnel_thru_httpproxy) {
/* We want "seamless" FTP operations through HTTP proxy tunnel */ /* We want "seamless" FTP operations through HTTP proxy tunnel */
@ -436,9 +430,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
/* The first thing we do is wait for the "220*" line: */ /* The first thing we do is wait for the "220*" line: */
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode != 220) { if(ftpcode != 220) {
failf(data, "This doesn't seem like a nice ftp-server response"); failf(data, "This doesn't seem like a nice ftp-server response");
@ -467,9 +461,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
FTPSENDF(conn, "USER %s", ftp->user); FTPSENDF(conn, "USER %s", ftp->user);
/* wait for feedback */ /* wait for feedback */
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode == 530) { if(ftpcode == 530) {
/* 530 User ... access denied /* 530 User ... access denied
@ -481,9 +475,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
/* 331 Password required for ... /* 331 Password required for ...
(the server requires to send the user's password too) */ (the server requires to send the user's password too) */
FTPSENDF(conn, "PASS %s", ftp->passwd); FTPSENDF(conn, "PASS %s", ftp->passwd);
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode == 530) { if(ftpcode == 530) {
/* 530 Login incorrect. /* 530 Login incorrect.
@ -516,8 +510,11 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
/* we may need to issue a KAUTH here to have access to the files /* we may need to issue a KAUTH here to have access to the files
* do it if user supplied a password * do it if user supplied a password
*/ */
if(data->state.passwd && *data->state.passwd) if(data->state.passwd && *data->state.passwd) {
Curl_krb_kauth(conn); result = Curl_krb_kauth(conn);
if(result)
return result;
}
#endif #endif
} }
else { else {
@ -529,9 +526,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
FTPSENDF(conn, "PWD", NULL); FTPSENDF(conn, "PWD", NULL);
/* wait for feedback */ /* wait for feedback */
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode == 257) { if(ftpcode == 257) {
char *dir = (char *)malloc(nread+1); char *dir = (char *)malloc(nread+1);
@ -544,7 +541,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
The directory name can contain any character; embedded double-quotes The directory name can contain any character; embedded double-quotes
should be escaped by double-quotes (the "quote-doubling" convention). should be escaped by double-quotes (the "quote-doubling" convention).
*/ */
if('\"' == *ptr) { if(dir && ('\"' == *ptr)) {
/* it started good */ /* it started good */
ptr++; ptr++;
while(ptr && *ptr) { while(ptr && *ptr) {
@ -570,6 +567,8 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
} }
else { else {
/* couldn't get the path */ /* couldn't get the path */
free(dir);
infof(data, "Failed to figure out path\n");
} }
} }
@ -594,7 +593,6 @@ CURLcode Curl_ftp_done(struct connectdata *conn)
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
struct FTP *ftp = conn->proto.ftp; struct FTP *ftp = conn->proto.ftp;
ssize_t nread; ssize_t nread;
char *buf = data->state.buffer; /* this is our buffer */
int ftpcode; int ftpcode;
CURLcode result=CURLE_OK; CURLcode result=CURLE_OK;
@ -633,11 +631,24 @@ CURLcode Curl_ftp_done(struct connectdata *conn)
conn->secondarysocket = -1; conn->secondarysocket = -1;
if(!ftp->no_transfer) { if(!ftp->no_transfer) {
/* now let's see what the server says about the transfer we just /* Let's see what the server says about the transfer we just performed,
performed: */ but lower the timeout as sometimes this connection has died while
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); the data has been transfered. This happens when doing through NATs
if(nread < 0) etc that abandon old silent connections.
return CURLE_OPERATION_TIMEOUTED; */
ftp->response_time = 60; /* give it only a minute for now */
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
ftp->response_time = 3600; /* set this back to one hour waits */
if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
failf(data, "control connection looks dead");
return result;
}
if(result)
return result;
if(!ftp->dont_check) { if(!ftp->dont_check) {
/* 226 Transfer complete, 250 Requested file action okay, completed. */ /* 226 Transfer complete, 250 Requested file action okay, completed. */
@ -680,9 +691,9 @@ CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
if (item->data) { if (item->data) {
FTPSENDF(conn, "%s", item->data); FTPSENDF(conn, "%s", item->data);
nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if (nread < 0) if (result)
return CURLE_OPERATION_TIMEOUTED; return result;
if (ftpcode >= 400) { if (ftpcode >= 400) {
failf(conn->data, "QUOT string not accepted: %s", item->data); failf(conn->data, "QUOT string not accepted: %s", item->data);
@ -711,9 +722,9 @@ CURLcode ftp_cwd(struct connectdata *conn, char *path)
CURLcode result; CURLcode result;
FTPSENDF(conn, "CWD %s", path); FTPSENDF(conn, "CWD %s", path);
nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if (nread < 0) if (result)
return CURLE_OPERATION_TIMEOUTED; return result;
if (ftpcode != 250) { if (ftpcode != 250) {
failf(conn->data, "Couldn't cd to %s", path); failf(conn->data, "Couldn't cd to %s", path);
@ -741,26 +752,34 @@ CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
again a grey area as the MDTM is not kosher RFC959 */ again a grey area as the MDTM is not kosher RFC959 */
FTPSENDF(conn, "MDTM %s", file); FTPSENDF(conn, "MDTM %s", file);
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode == 213) { switch(ftpcode) {
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the case 213:
last .sss part is optional and means fractions of a second */ {
int year, month, day, hour, minute, second; /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d", last .sss part is optional and means fractions of a second */
&year, &month, &day, &hour, &minute, &second)) { int year, month, day, hour, minute, second;
/* we have a time, reformat it */ if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
time_t secs=time(NULL); &year, &month, &day, &hour, &minute, &second)) {
sprintf(buf, "%04d%02d%02d %02d:%02d:%02d", /* we have a time, reformat it */
year, month, day, hour, minute, second); time_t secs=time(NULL);
/* now, convert this into a time() value: */ sprintf(buf, "%04d%02d%02d %02d:%02d:%02d",
conn->data->info.filetime = curl_getdate(buf, &secs); year, month, day, hour, minute, second);
} /* now, convert this into a time() value: */
else { conn->data->info.filetime = curl_getdate(buf, &secs);
infof(conn->data, "unsupported MDTM reply format\n"); }
} }
break;
default:
infof(conn->data, "unsupported MDTM reply format\n");
break;
case 550: /* "No such file or directory" */
failf(conn->data, "Given file does not exist");
result = CURLE_FTP_COULDNT_RETR_FILE;
break;
} }
return result; return result;
} }
@ -778,14 +797,13 @@ static CURLcode ftp_transfertype(struct connectdata *conn,
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
int ftpcode; int ftpcode;
ssize_t nread; ssize_t nread;
char *buf=data->state.buffer;
CURLcode result; CURLcode result;
FTPSENDF(conn, "TYPE %s", ascii?"A":"I"); FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode != 200) { if(ftpcode != 200) {
failf(data, "Couldn't set %s mode", failf(data, "Couldn't set %s mode",
@ -814,9 +832,9 @@ CURLcode ftp_getsize(struct connectdata *conn, char *file,
CURLcode result; CURLcode result;
FTPSENDF(conn, "SIZE %s", file); FTPSENDF(conn, "SIZE %s", file);
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode == 213) { if(ftpcode == 213) {
/* get the size from the ascii string: */ /* get the size from the ascii string: */
@ -975,7 +993,6 @@ CURLcode ftp_use_port(struct connectdata *conn)
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
int portsock=-1; int portsock=-1;
ssize_t nread; ssize_t nread;
char *buf = data->state.buffer; /* this is our buffer */
int ftpcode; /* receive FTP response codes in this */ int ftpcode; /* receive FTP response codes in this */
CURLcode result; CURLcode result;
@ -1155,9 +1172,9 @@ CURLcode ftp_use_port(struct connectdata *conn)
return result; return result;
} }
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if (ftpcode != 200) { if (ftpcode != 200) {
failf(data, "Server does not grok %s", *modep); failf(data, "Server does not grok %s", *modep);
@ -1301,9 +1318,9 @@ CURLcode ftp_use_port(struct connectdata *conn)
return result; return result;
} }
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode != 200) { if(ftpcode != 200) {
failf(data, "Server does not grok PORT, try without it!"); failf(data, "Server does not grok PORT, try without it!");
@ -1375,9 +1392,9 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
result = Curl_ftpsendf(conn, "%s", mode[modeoff]); result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
if(result) if(result)
return result; return result;
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if (ftpcode == results[modeoff]) if (ftpcode == results[modeoff])
break; break;
} }
@ -1522,7 +1539,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
ssize_t nread; ssize_t nread;
int ftpcode; /* for ftp status */ int ftpcode; /* for ftp status */
/* the ftp struct is already inited in ftp_connect() */ /* the ftp struct is already inited in Curl_ftp_connect() */
struct FTP *ftp = conn->proto.ftp; struct FTP *ftp = conn->proto.ftp;
long *bytecountp = ftp->bytecountp; long *bytecountp = ftp->bytecountp;
@ -1582,8 +1599,8 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
readthisamountnow = BUFSIZE; readthisamountnow = BUFSIZE;
actuallyread = actuallyread =
data->set.fread(data->state.buffer, 1, readthisamountnow, conn->fread(data->state.buffer, 1, readthisamountnow,
data->set.in); conn->fread_in);
passed += actuallyread; passed += actuallyread;
if(actuallyread != readthisamountnow) { if(actuallyread != readthisamountnow) {
@ -1614,7 +1631,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
} }
} }
/* Send everything on data->set.in to the socket */ /* Send everything on data->state.in to the socket */
if(data->set.ftp_append) { if(data->set.ftp_append) {
/* we append onto the file instead of rewriting it */ /* we append onto the file instead of rewriting it */
FTPSENDF(conn, "APPE %s", ftp->file); FTPSENDF(conn, "APPE %s", ftp->file);
@ -1623,9 +1640,9 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
FTPSENDF(conn, "STOR %s", ftp->file); FTPSENDF(conn, "STOR %s", ftp->file);
} }
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode>=400) { if(ftpcode>=400) {
failf(data, "Failed FTP upload:%s", buf+3); failf(data, "Failed FTP upload:%s", buf+3);
@ -1799,9 +1816,9 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
FTPSENDF(conn, "REST %d", conn->resume_from); FTPSENDF(conn, "REST %d", conn->resume_from);
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if(ftpcode != 350) { if(ftpcode != 350) {
failf(data, "Couldn't use REST: %s", buf+4); failf(data, "Couldn't use REST: %s", buf+4);
@ -1812,9 +1829,9 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
FTPSENDF(conn, "RETR %s", ftp->file); FTPSENDF(conn, "RETR %s", ftp->file);
} }
nread = Curl_GetFTPResponse(buf, conn, &ftpcode); result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(nread < 0) if(result)
return CURLE_OPERATION_TIMEOUTED; return result;
if((ftpcode == 150) || (ftpcode == 125)) { if((ftpcode == 150) || (ftpcode == 125)) {
@ -1919,7 +1936,7 @@ CURLcode ftp_perform(struct connectdata *conn,
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
char *buf = data->state.buffer; /* this is our buffer */ char *buf = data->state.buffer; /* this is our buffer */
/* the ftp struct is already inited in ftp_connect() */ /* the ftp struct is already inited in Curl_ftp_connect() */
struct FTP *ftp = conn->proto.ftp; struct FTP *ftp = conn->proto.ftp;
/* Send any QUOTE strings? */ /* Send any QUOTE strings? */
@ -1980,7 +1997,7 @@ CURLcode ftp_perform(struct connectdata *conn,
well, we "emulate" a HTTP-style header in our output. */ well, we "emulate" a HTTP-style header in our output. */
#ifdef HAVE_STRFTIME #ifdef HAVE_STRFTIME
if(data->set.get_filetime && data->info.filetime) { if(data->set.get_filetime && (data->info.filetime>=0) ) {
struct tm *tm; struct tm *tm;
#ifdef HAVE_LOCALTIME_R #ifdef HAVE_LOCALTIME_R
struct tm buffer; struct tm buffer;

View File

@ -29,8 +29,8 @@ CURLcode Curl_ftp_done(struct connectdata *conn);
CURLcode Curl_ftp_connect(struct connectdata *conn); CURLcode Curl_ftp_connect(struct connectdata *conn);
CURLcode Curl_ftp_disconnect(struct connectdata *conn); CURLcode Curl_ftp_disconnect(struct connectdata *conn);
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...); CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
int Curl_GetFTPResponse(char *buf, struct connectdata *conn, CURLcode Curl_GetFTPResponse(int *nread, struct connectdata *conn,
int *ftpcode); int *ftpcode);
CURLcode Curl_ftp_nextconnect(struct connectdata *conn); CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
#endif #endif

View File

@ -158,6 +158,9 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
case CURLINFO_CONTENT_TYPE: case CURLINFO_CONTENT_TYPE:
*param_charp = data->info.contenttype; *param_charp = data->info.contenttype;
break; break;
case CURLINFO_PRIVATE:
*param_charp = data->set.private?data->set.private:(char *)"";
break;
default: default:
return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_BAD_FUNCTION_ARGUMENT;
} }

View File

@ -88,7 +88,7 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
void Curl_global_host_cache_init(void) void Curl_global_host_cache_init(void)
{ {
if (!host_cache_initialized) { if (!host_cache_initialized) {
Curl_hash_init(&hostname_cache, 7, Curl_freeaddrinfo); Curl_hash_init(&hostname_cache, 7, Curl_freednsinfo);
host_cache_initialized = 1; host_cache_initialized = 1;
} }
} }
@ -287,17 +287,25 @@ struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
/* /*
* This is a wrapper function for freeing name information in a protocol * This is a wrapper function for freeing name information in a protocol
* independent way. This takes care of using the appropriate underlaying * independent way. This takes care of using the appropriate underlaying
* proper function. * function.
*/ */
void Curl_freeaddrinfo(void *freethis) void Curl_freeaddrinfo(Curl_addrinfo *p)
{
#ifdef ENABLE_IPV6
freeaddrinfo(p);
#else
free(p);
#endif
}
/*
* Free a cache dns entry.
*/
void Curl_freednsinfo(void *freethis)
{ {
struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis; struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
#ifdef ENABLE_IPV6 Curl_freeaddrinfo(p->addr);
freeaddrinfo(p->addr);
#else
free(p->addr);
#endif
free(p); free(p);
} }
@ -623,16 +631,28 @@ static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
&h, /* DIFFERENCE */ &h, /* DIFFERENCE */
&h_errnop); &h_errnop);
/* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
sudden this function seems to be setting EAGAIN if the given buffer sudden this function returns EAGAIN if the given buffer size is too
size is too small. Previous versions are known to return ERANGE for small. Previous versions are known to return ERANGE for the same
the same. */ problem.
This wouldn't be such a big problem if older versions wouldn't
sometimes return EAGAIN on a common failure case. Alas, we can't
assume that EAGAIN *or* ERANGE means ERANGE for any given version of
glibc.
For now, we do that and thus we may call the function repeatedly and
fail for older glibc versions that return EAGAIN, until we run out
of buffer size (step_size grows beyond CURL_NAMELOOKUP_SIZE).
If anyone has a better fix, please tell us!
*/
if((ERANGE == res) || (EAGAIN == res)) { if((ERANGE == res) || (EAGAIN == res)) {
step_size+=200; step_size+=200;
continue; continue;
} }
break; break;
} while(1); } while(step_size <= CURL_NAMELOOKUP_SIZE);
if(!h) /* failure */ if(!h) /* failure */
res=1; res=1;

View File

@ -65,7 +65,10 @@ struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
void Curl_scan_cache_used(void *user, void *ptr); void Curl_scan_cache_used(void *user, void *ptr);
/* free name info */ /* free name info */
void Curl_freeaddrinfo(void *freethis); void Curl_freeaddrinfo(Curl_addrinfo *freeaddr);
/* free cached name info */
void Curl_freednsinfo(void *freethis);
#ifdef MALLOCDEBUG #ifdef MALLOCDEBUG
void curl_freeaddrinfo(struct addrinfo *freethis, void curl_freeaddrinfo(struct addrinfo *freethis,

View File

@ -98,12 +98,65 @@
#include "memdebug.h" #include "memdebug.h"
#endif #endif
/* fread() emulation to provide POST and/or request data */
static int readmoredata(char *buffer,
size_t size,
size_t nitems,
void *userp)
{
struct connectdata *conn = (struct connectdata *)userp;
struct HTTP *http = conn->proto.http;
int fullsize = size * nitems;
if(0 == http->postsize)
/* nothing to return */
return 0;
/* make sure that a HTTP request is never sent away chunked! */
conn->bits.forbidchunk= (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
if(http->postsize <= fullsize) {
memcpy(buffer, http->postdata, http->postsize);
fullsize = http->postsize;
if(http->backup.postsize) {
/* move backup data into focus and continue on that */
http->postdata = http->backup.postdata;
http->postsize = http->backup.postsize;
conn->fread = http->backup.fread;
conn->fread_in = http->backup.fread_in;
http->sending++; /* move one step up */
http->backup.postsize=0;
}
else
http->postsize = 0;
return fullsize;
}
memcpy(buffer, http->postdata, fullsize);
http->postdata += fullsize;
http->postsize -= fullsize;
return fullsize;
}
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* /*
* The add_buffer series of functions are used to build one large memory chunk * The add_buffer series of functions are used to build one large memory chunk
* from repeated function invokes. Used so that the entire HTTP request can * from repeated function invokes. Used so that the entire HTTP request can
* be sent in one go. * be sent in one go.
*/ */
struct send_buffer {
char *buffer;
size_t size_max;
size_t size_used;
};
typedef struct send_buffer send_buffer;
static CURLcode static CURLcode
add_buffer(send_buffer *in, const void *inptr, size_t size); add_buffer(send_buffer *in, const void *inptr, size_t size);
@ -126,44 +179,66 @@ send_buffer *add_buffer_init(void)
* add_buffer_send() sends a buffer and frees all associated memory. * add_buffer_send() sends a buffer and frees all associated memory.
*/ */
static static
CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in, CURLcode add_buffer_send(send_buffer *in,
long *bytes_written) int sockfd,
struct connectdata *conn,
long *bytes_written) /* add the number of sent
bytes to this counter */
{ {
ssize_t amount; ssize_t amount;
CURLcode res; CURLcode res;
char *ptr; char *ptr;
int size; int size;
struct HTTP *http = conn->proto.http;
/* The looping below is required since we use non-blocking sockets, but due /* The looping below is required since we use non-blocking sockets, but due
to the circumstances we will just loop and try again and again etc */ to the circumstances we will just loop and try again and again etc */
ptr = in->buffer; ptr = in->buffer;
size = in->size_used; size = in->size_used;
do {
res = Curl_write(conn, sockfd, ptr, size, &amount);
if(CURLE_OK != res) res = Curl_write(conn, sockfd, ptr, size, &amount);
break;
if(CURLE_OK == res) {
if(conn->data->set.verbose) if(conn->data->set.verbose)
/* this data _may_ contain binary stuff */ /* this data _may_ contain binary stuff */
Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount); Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount);
*bytes_written += amount;
if(amount != size) { if(amount != size) {
/* The whole request could not be sent in one system call. We must queue
it up and send it later when we get the chance. We must not loop here
and wait until it might work again. */
size -= amount; size -= amount;
ptr += amount; ptr += amount;
/* backup the currently set pointers */
http->backup.fread = conn->fread;
http->backup.fread_in = conn->fread_in;
http->backup.postdata = http->postdata;
http->backup.postsize = http->postsize;
/* set the new pointers for the request-sending */
conn->fread = (curl_read_callback)readmoredata;
conn->fread_in = (void *)conn;
http->postdata = ptr;
http->postsize = size;
http->send_buffer = in;
http->sending = HTTPSEND_REQUEST;
return CURLE_OK;
} }
else
break;
} while(1);
/* the full buffer was sent, clean up and return */
}
if(in->buffer) if(in->buffer)
free(in->buffer); free(in->buffer);
free(in); free(in);
*bytes_written += amount;
return res; return res;
} }
@ -223,21 +298,75 @@ CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
/* end of the add_buffer functions */ /* end of the add_buffer functions */
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/*
* Curl_compareheader()
*
* Returns TRUE if 'headerline' contains the 'header' with given 'content'.
* Pass headers WITH the colon.
*/
bool
Curl_compareheader(char *headerline, /* line to check */
const char *header, /* header keyword _with_ colon */
const char *content) /* content string to find */
{
/* RFC2616, section 4.2 says: "Each header field consists of a name followed
* by a colon (":") and the field value. Field names are case-insensitive.
* The field value MAY be preceded by any amount of LWS, though a single SP
* is preferred." */
size_t hlen = strlen(header);
size_t clen;
size_t len;
char *start;
char *end;
if(!strnequal(headerline, header, hlen))
return FALSE; /* doesn't start with header */
/* pass the header */
start = &headerline[hlen];
/* pass all white spaces */
while(*start && isspace((int)*start))
start++;
/* find the end of the header line */
end = strchr(start, '\r'); /* lines end with CRLF */
if(!end) {
/* in case there's a non-standard compliant line here */
end = strchr(start, '\n');
if(!end)
/* hm, there's no line ending here, use the zero byte! */
end = strchr(start, '\0');
}
len = end-start; /* length of the content part of the input line */
clen = strlen(content); /* length of the word to find */
/* find the content string in the rest of the line */
for(;len>=clen;len--, start++) {
if(strnequal(start, content, clen))
return TRUE; /* match! */
}
return FALSE; /* no match */
}
/* /*
* This function checks the linked list of custom HTTP headers for a particular * This function checks the linked list of custom HTTP headers for a particular
* header (prefix). * header (prefix).
*/ */
static bool checkheaders(struct SessionHandle *data, const char *thisheader) static char *checkheaders(struct SessionHandle *data, const char *thisheader)
{ {
struct curl_slist *head; struct curl_slist *head;
size_t thislen = strlen(thisheader); size_t thislen = strlen(thisheader);
for(head = data->set.headers; head; head=head->next) { for(head = data->set.headers; head; head=head->next) {
if(strnequal(head->data, thisheader, thislen)) { if(strnequal(head->data, thisheader, thislen))
return TRUE; return head->data;
}
} }
return FALSE; return NULL;
} }
/* /*
@ -440,6 +569,10 @@ CURLcode Curl_http_connect(struct connectdata *conn)
if(conn->bits.user_passwd && !data->state.this_is_a_follow) { if(conn->bits.user_passwd && !data->state.this_is_a_follow) {
/* Authorization: is requested, this is not a followed location, get the /* Authorization: is requested, this is not a followed location, get the
original host name */ original host name */
if (data->state.auth_host)
/* Free to avoid leaking memory on multiple requests*/
free(data->state.auth_host);
data->state.auth_host = strdup(conn->hostname); data->state.auth_host = strdup(conn->hostname);
} }
@ -454,13 +587,21 @@ CURLcode Curl_http_done(struct connectdata *conn)
data=conn->data; data=conn->data;
http=conn->proto.http; http=conn->proto.http;
/* set the proper values (possibly modified on POST) */
conn->fread = data->set.fread; /* restore */
conn->fread_in = data->set.in; /* restore */
if(http->send_buffer) {
send_buffer *buff = http->send_buffer;
free(buff->buffer);
free(buff);
}
if(HTTPREQ_POST_FORM == data->set.httpreq) { if(HTTPREQ_POST_FORM == data->set.httpreq) {
conn->bytecount = http->readbytecount + http->writebytecount; conn->bytecount = http->readbytecount + http->writebytecount;
Curl_formclean(http->sendit); /* Now free that whole lot */ Curl_formclean(http->sendit); /* Now free that whole lot */
data->set.fread = http->storefread; /* restore */
data->set.in = http->in; /* restore */
} }
else if(HTTPREQ_PUT == data->set.httpreq) else if(HTTPREQ_PUT == data->set.httpreq)
conn->bytecount = http->readbytecount + http->writebytecount; conn->bytecount = http->readbytecount + http->writebytecount;
@ -475,7 +616,6 @@ CURLcode Curl_http_done(struct connectdata *conn)
return CURLE_OK; return CURLE_OK;
} }
CURLcode Curl_http(struct connectdata *conn) CURLcode Curl_http(struct connectdata *conn)
{ {
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
@ -523,7 +663,7 @@ CURLcode Curl_http(struct connectdata *conn)
host due to a location-follow, we do some weirdo checks here */ host due to a location-follow, we do some weirdo checks here */
if(!data->state.this_is_a_follow || if(!data->state.this_is_a_follow ||
!data->state.auth_host || !data->state.auth_host ||
strequal(data->state.auth_host, conn->hostname)) { curl_strequal(data->state.auth_host, conn->hostname)) {
sprintf(data->state.buffer, "%s:%s", sprintf(data->state.buffer, "%s:%s",
data->state.user, data->state.passwd); data->state.user, data->state.passwd);
if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer), if(Curl_base64_encode(data->state.buffer, strlen(data->state.buffer),
@ -547,12 +687,30 @@ CURLcode Curl_http(struct connectdata *conn)
conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie); conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie);
} }
if(!conn->bits.upload_chunky && (data->set.httpreq != HTTPREQ_GET)) {
/* not a chunky transfer but data is to be sent */
char *ptr = checkheaders(data, "Transfer-Encoding:");
if(ptr) {
/* Some kind of TE is requested, check if 'chunked' is chosen */
if(Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"))
/* we have been told explicitly to upload chunky so deal with it! */
conn->bits.upload_chunky = TRUE;
}
}
if(conn->bits.upload_chunky) { if(conn->bits.upload_chunky) {
/* RFC2616 section 4.4:
Messages MUST NOT include both a Content-Length header field and a
non-identity transfer-coding. If the message does include a non-
identity transfer-coding, the Content-Length MUST be ignored. */
if(!checkheaders(data, "Transfer-Encoding:")) { if(!checkheaders(data, "Transfer-Encoding:")) {
te = "Transfer-Encoding: chunked\r\n"; te = "Transfer-Encoding: chunked\r\n";
} }
/* else else {
our header was already added, what to do now? */ /* The "Transfer-Encoding:" header was already added. */
te = "";
}
} }
if(data->cookies) { if(data->cookies) {
@ -847,16 +1005,16 @@ CURLcode Curl_http(struct connectdata *conn)
return CURLE_HTTP_POST_ERROR; return CURLE_HTTP_POST_ERROR;
} }
http->storefread = data->set.fread; /* backup */ /* set the read function to read from the generated form data */
http->in = data->set.in; /* backup */ conn->fread = (curl_read_callback)Curl_FormReader;
conn->fread_in = &http->form;
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, http->sending = HTTPSEND_BODY;
"Content-Length: %d\r\n", http->postsize);
if(!conn->bits.upload_chunky)
/* only add Content-Length if not uploading chunked */
add_bufferf(req_buffer,
"Content-Length: %d\r\n", http->postsize);
if(!checkheaders(data, "Expect:")) { if(!checkheaders(data, "Expect:")) {
/* if not disabled explicitly we add a Expect: 100-continue /* if not disabled explicitly we add a Expect: 100-continue
@ -896,7 +1054,7 @@ CURLcode Curl_http(struct connectdata *conn)
Curl_pgrsSetUploadSize(data, http->postsize); Curl_pgrsSetUploadSize(data, http->postsize);
/* fire away the whole request to the server */ /* fire away the whole request to the server */
result = add_buffer_send(conn->firstsocket, conn, req_buffer, result = add_buffer_send(req_buffer, conn->firstsocket, conn,
&data->info.request_size); &data->info.request_size);
if(result) if(result)
failf(data, "Failed sending POST request"); failf(data, "Failed sending POST request");
@ -914,22 +1072,22 @@ CURLcode Curl_http(struct connectdata *conn)
case HTTPREQ_PUT: /* Let's PUT the data to the server! */ case HTTPREQ_PUT: /* Let's PUT the data to the server! */
if(data->set.infilesize>0) { if((data->set.infilesize>0) && !conn->bits.upload_chunky)
/* only add Content-Length if not uploading chunked */
add_bufferf(req_buffer, add_bufferf(req_buffer,
"Content-Length: %d\r\n\r\n", /* file size */ "Content-Length: %d\r\n", /* file size */
data->set.infilesize ); data->set.infilesize );
}
else add_bufferf(req_buffer, "\r\n");
add_bufferf(req_buffer, "\015\012");
/* set the upload size to the progress meter */ /* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, data->set.infilesize); Curl_pgrsSetUploadSize(data, data->set.infilesize);
/* this sends the buffer and frees all the buffer resources */ /* this sends the buffer and frees all the buffer resources */
result = add_buffer_send(conn->firstsocket, conn, req_buffer, result = add_buffer_send(req_buffer, conn->firstsocket, conn,
&data->info.request_size); &data->info.request_size);
if(result) if(result)
failf(data, "Faied sending POST request"); failf(data, "Failed sending POST request");
else else
/* prepare for transfer */ /* prepare for transfer */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
@ -943,14 +1101,20 @@ CURLcode Curl_http(struct connectdata *conn)
case HTTPREQ_POST: case HTTPREQ_POST:
/* this is the simple POST, using x-www-form-urlencoded style */ /* this is the simple POST, using x-www-form-urlencoded style */
if(!checkheaders(data, "Content-Length:")) if(!conn->bits.upload_chunky) {
/* we allow replacing this header, although it isn't very wise to /* We only set Content-Length and allow a custom Content-Length if
actually set your own */ we don't upload data chunked, as RFC2616 forbids us to set both
add_bufferf(req_buffer, kinds of headers (Transfer-Encoding: chunked and Content-Length) */
"Content-Length: %d\r\n",
data->set.postfieldsize? if(!checkheaders(data, "Content-Length:"))
data->set.postfieldsize: /* we allow replacing this header, although it isn't very wise to
(data->set.postfields?strlen(data->set.postfields):0) ); actually set your own */
add_bufferf(req_buffer,
"Content-Length: %d\r\n",
data->set.postfieldsize?
data->set.postfieldsize:
(data->set.postfields?strlen(data->set.postfields):0) );
}
if(!checkheaders(data, "Content-Type:")) if(!checkheaders(data, "Content-Type:"))
add_bufferf(req_buffer, add_bufferf(req_buffer,
@ -958,18 +1122,28 @@ CURLcode Curl_http(struct connectdata *conn)
add_buffer(req_buffer, "\r\n", 2); add_buffer(req_buffer, "\r\n", 2);
/* and here comes the actual data */ /* and here we setup the pointers to the actual data */
if(data->set.postfieldsize && data->set.postfields) { if(data->set.postfields) {
add_buffer(req_buffer, data->set.postfields, if(data->set.postfieldsize)
data->set.postfieldsize); http->postsize = data->set.postfieldsize;
} else
else if(data->set.postfields) http->postsize = strlen(data->set.postfields);
add_bufferf(req_buffer, http->postdata = data->set.postfields;
"%s",
data->set.postfields );
/* issue the request */ http->sending = HTTPSEND_BODY;
result = add_buffer_send(conn->firstsocket, conn, req_buffer,
conn->fread = (curl_read_callback)readmoredata;
conn->fread_in = (void *)conn;
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
}
else
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, data->set.infilesize);
/* issue the request, headers-only */
result = add_buffer_send(req_buffer, conn->firstsocket, conn,
&data->info.request_size); &data->info.request_size);
if(result) if(result)
@ -978,15 +1152,15 @@ CURLcode Curl_http(struct connectdata *conn)
result = result =
Curl_Transfer(conn, conn->firstsocket, -1, TRUE, Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
&http->readbytecount, &http->readbytecount,
data->set.postfields?-1:conn->firstsocket, conn->firstsocket,
data->set.postfields?NULL:&http->writebytecount); &http->writebytecount);
break; break;
default: default:
add_buffer(req_buffer, "\r\n", 2); add_buffer(req_buffer, "\r\n", 2);
/* issue the request */ /* issue the request */
result = add_buffer_send(conn->firstsocket, conn, req_buffer, result = add_buffer_send(req_buffer, conn->firstsocket, conn,
&data->info.request_size); &data->info.request_size);
if(result) if(result)
@ -995,7 +1169,8 @@ CURLcode Curl_http(struct connectdata *conn)
/* HTTP GET/HEAD download: */ /* HTTP GET/HEAD download: */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
&http->readbytecount, &http->readbytecount,
-1, NULL); /* nothing to upload */ http->postdata?conn->firstsocket:-1,
http->postdata?&http->writebytecount:NULL);
} }
if(result) if(result)
return result; return result;

View File

@ -24,6 +24,10 @@
* $Id$ * $Id$
***************************************************************************/ ***************************************************************************/
#ifndef CURL_DISABLE_HTTP #ifndef CURL_DISABLE_HTTP
bool Curl_compareheader(char *headerline, /* line to check */
const char *header, /* header keyword _with_ colon */
const char *content); /* content string to find */
/* ftp can use this as well */ /* ftp can use this as well */
CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
int tunnelsocket, int tunnelsocket,

View File

@ -29,5 +29,40 @@ extern char *Curl_if2ip(char *interface, char *buf, int buf_size);
#else #else
#define Curl_if2ip(a,b,c) NULL #define Curl_if2ip(a,b,c) NULL
#endif #endif
#ifdef __INTERIX
/* Nedelcho Stanev's work-around for SFU 3.0 */
struct ifreq {
#define IFNAMSIZ 16
#define IFHWADDRLEN 6
union {
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
} ifr_ifrn;
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short ifru_flags;
int ifru_metric;
int ifru_mtu;
} ifr_ifru;
};
/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the
C code. */
#define ifr_dstaddr ifr_addr
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
#define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
#define ifr_metric ifr_ifru.ifru_metric /* metric */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */
#endif /* interix */
#endif #endif

View File

@ -202,6 +202,7 @@ krb4_auth(void *app_data, struct connectdata *conn)
ssize_t nread; ssize_t nread;
int l = sizeof(conn->local_addr); int l = sizeof(conn->local_addr);
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
CURLcode result;
if(getsockname(conn->firstsocket, if(getsockname(conn->firstsocket,
(struct sockaddr *)LOCAL_ADDR, &l) < 0) (struct sockaddr *)LOCAL_ADDR, &l) < 0)
@ -246,13 +247,15 @@ krb4_auth(void *app_data, struct connectdata *conn)
return AUTH_CONTINUE; return AUTH_CONTINUE;
} }
if(Curl_ftpsendf(conn, "ADAT %s", p)) result = Curl_ftpsendf(conn, "ADAT %s", p);
free(p);
if(result)
return -2; return -2;
nread = Curl_GetFTPResponse(data->state.buffer, conn, NULL); if(Curl_GetFTPResponse(&nread, conn, NULL))
if(nread < 0)
return -1; return -1;
free(p);
if(data->state.buffer[0] != '2'){ if(data->state.buffer[0] != '2'){
Curl_failf(data, "Server didn't accept auth data"); Curl_failf(data, "Server didn't accept auth data");
@ -299,7 +302,7 @@ struct Curl_sec_client_mech Curl_krb4_client_mech = {
krb4_decode krb4_decode
}; };
void Curl_krb_kauth(struct connectdata *conn) CURLcode Curl_krb_kauth(struct connectdata *conn)
{ {
des_cblock key; des_cblock key;
des_key_schedule schedule; des_key_schedule schedule;
@ -309,18 +312,19 @@ void Curl_krb_kauth(struct connectdata *conn)
char passwd[100]; char passwd[100];
int tmp; int tmp;
ssize_t nread; ssize_t nread;
int save; int save;
CURLcode result;
save = Curl_set_command_prot(conn, prot_private); save = Curl_set_command_prot(conn, prot_private);
if(Curl_ftpsendf(conn, "SITE KAUTH %s", conn->data->state.user)) result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->data->state.user);
return;
nread = Curl_GetFTPResponse(conn->data->state.buffer, if(result)
conn, NULL); return result;
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/; result = Curl_GetFTPResponse(&nread, conn, NULL);
if(result)
return result;
if(conn->data->state.buffer[0] != '3'){ if(conn->data->state.buffer[0] != '3'){
Curl_set_command_prot(conn, save); Curl_set_command_prot(conn, save);
@ -331,7 +335,7 @@ void Curl_krb_kauth(struct connectdata *conn)
if(!p) { if(!p) {
Curl_failf(conn->data, "Bad reply from server"); Curl_failf(conn->data, "Bad reply from server");
Curl_set_command_prot(conn, save); Curl_set_command_prot(conn, save);
return; return CURLE_FTP_WEIRD_SERVER_REPLY;
} }
p += 2; p += 2;
@ -339,7 +343,7 @@ void Curl_krb_kauth(struct connectdata *conn)
if(tmp < 0) { if(tmp < 0) {
Curl_failf(conn->data, "Failed to decode base64 in reply.\n"); Curl_failf(conn->data, "Failed to decode base64 in reply.\n");
Curl_set_command_prot(conn, save); Curl_set_command_prot(conn, save);
return; return CURLE_FTP_WEIRD_SERVER_REPLY;
} }
tkt.length = tmp; tkt.length = tmp;
tktcopy.length = tkt.length; tktcopy.length = tkt.length;
@ -348,7 +352,7 @@ void Curl_krb_kauth(struct connectdata *conn)
if(!p) { if(!p) {
Curl_failf(conn->data, "Bad reply from server"); Curl_failf(conn->data, "Bad reply from server");
Curl_set_command_prot(conn, save); Curl_set_command_prot(conn, save);
return; return CURLE_FTP_WEIRD_SERVER_REPLY;
} }
name = p + 2; name = p + 2;
for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++); for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++);
@ -376,19 +380,21 @@ void Curl_krb_kauth(struct connectdata *conn)
if(Curl_base64_encode(tktcopy.dat, tktcopy.length, &p) < 0) { if(Curl_base64_encode(tktcopy.dat, tktcopy.length, &p) < 0) {
failf(conn->data, "Out of memory base64-encoding."); failf(conn->data, "Out of memory base64-encoding.");
Curl_set_command_prot(conn, save); Curl_set_command_prot(conn, save);
return; return CURLE_OUT_OF_MEMORY;
} }
memset (tktcopy.dat, 0, tktcopy.length); memset (tktcopy.dat, 0, tktcopy.length);
if(Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p)) result = Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p);
return;
nread = Curl_GetFTPResponse(conn->data->state.buffer,
conn, NULL);
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/;
free(p); free(p);
if(result)
return result;
result = Curl_GetFTPResponse(&nread, conn, NULL);
if(result)
return result;
Curl_set_command_prot(conn, save); Curl_set_command_prot(conn, save);
return CURLE_OK;
} }
#endif /* KRB4 */ #endif /* KRB4 */

View File

@ -22,6 +22,6 @@
* *
* $Id$ * $Id$
***************************************************************************/ ***************************************************************************/
void Curl_krb_kauth(struct connectdata *conn); CURLcode Curl_krb_kauth(struct connectdata *conn);
#endif #endif

View File

@ -313,9 +313,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
easy->easy_handle->hostcache = Curl_global_host_cache_get(); easy->easy_handle->hostcache = Curl_global_host_cache_get();
} }
else { else {
if (multi->hostcache == NULL) { if (multi->hostcache == NULL)
multi->hostcache = Curl_hash_alloc(7, Curl_freeaddrinfo); multi->hostcache = Curl_hash_alloc(7, Curl_freednsinfo);
}
easy->easy_handle->hostcache = multi->hostcache; easy->easy_handle->hostcache = multi->hostcache;
} }

View File

@ -278,32 +278,6 @@ Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length)
return tx; return tx;
} }
int
Curl_sec_vfprintf2(struct connectdata *conn, FILE *f, const char *fmt, va_list ap)
{
char *buf;
int ret;
if(conn->data_prot == prot_clear)
return vfprintf(f, fmt, ap);
else {
buf = aprintf(fmt, ap);
ret = buffer_write(&conn->out_buffer, buf, strlen(buf));
free(buf);
return ret;
}
}
int
Curl_sec_fprintf2(struct connectdata *conn, FILE *f, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = Curl_sec_vfprintf2(conn, f, fmt, ap);
va_end(ap);
return ret;
}
int int
Curl_sec_putc(struct connectdata *conn, int c, FILE *F) Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
{ {
@ -313,7 +287,8 @@ Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
buffer_write(&conn->out_buffer, &ch, 1); buffer_write(&conn->out_buffer, &ch, 1);
if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) { if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) {
Curl_sec_write(conn, fileno(F), conn->out_buffer.data, conn->out_buffer.index); Curl_sec_write(conn, fileno(F), conn->out_buffer.data,
conn->out_buffer.index);
conn->out_buffer.index = 0; conn->out_buffer.index = 0;
} }
return c; return c;
@ -346,53 +321,6 @@ Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
return code; return code;
} }
/* modified to return how many bytes written, or -1 on error ***/
int
Curl_sec_vfprintf(struct connectdata *conn, FILE *f, const char *fmt, va_list ap)
{
int ret = 0;
char *buf;
void *enc;
int len;
if(!conn->sec_complete)
return vfprintf(f, fmt, ap);
buf = aprintf(fmt, ap);
len = (conn->mech->encode)(conn->app_data, buf, strlen(buf),
conn->command_prot, &enc,
conn);
free(buf);
if(len < 0) {
failf(conn->data, "Failed to encode command.");
return -1;
}
if(Curl_base64_encode(enc, len, &buf) < 0){
failf(conn->data, "Out of memory base64-encoding.");
return -1;
}
if(conn->command_prot == prot_safe)
ret = fprintf(f, "MIC %s", buf);
else if(conn->command_prot == prot_private)
ret = fprintf(f, "ENC %s", buf);
else if(conn->command_prot == prot_confidential)
ret = fprintf(f, "CONF %s", buf);
free(buf);
return ret;
}
int
Curl_sec_fprintf(struct connectdata *conn, FILE *f, const char *fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = Curl_sec_vfprintf(conn, f, fmt, ap);
va_end(ap);
return ret;
}
enum protection_level enum protection_level
Curl_set_command_prot(struct connectdata *conn, enum protection_level level) Curl_set_command_prot(struct connectdata *conn, enum protection_level level)
{ {
@ -414,14 +342,14 @@ sec_prot_internal(struct connectdata *conn, int level)
} }
if(level){ if(level){
int code;
if(Curl_ftpsendf(conn, "PBSZ %u", s)) if(Curl_ftpsendf(conn, "PBSZ %u", s))
return -1; return -1;
nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, NULL); if(Curl_GetFTPResponse(&nread, conn, &code))
if(nread < 0)
return -1; return -1;
if(conn->data->state.buffer[0] != '2'){ if(code/100 != '2'){
failf(conn->data, "Failed to set protection buffer size."); failf(conn->data, "Failed to set protection buffer size.");
return -1; return -1;
} }
@ -437,8 +365,7 @@ sec_prot_internal(struct connectdata *conn, int level)
if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"])) if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"]))
return -1; return -1;
nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, NULL); if(Curl_GetFTPResponse(&nread, conn, NULL))
if(nread < 0)
return -1; return -1;
if(conn->data->state.buffer[0] != '2'){ if(conn->data->state.buffer[0] != '2'){
@ -496,8 +423,7 @@ Curl_sec_login(struct connectdata *conn)
if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name)) if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name))
return -1; return -1;
nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, &ftpcode); if(Curl_GetFTPResponse(&nread, conn, &ftpcode))
if(nread < 0)
return -1; return -1;
if(conn->data->state.buffer[0] != '3'){ if(conn->data->state.buffer[0] != '3'){

View File

@ -154,9 +154,19 @@ void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
vsnprintf(data->set.errorbuffer, CURL_ERROR_SIZE, fmt, ap); vsnprintf(data->set.errorbuffer, CURL_ERROR_SIZE, fmt, ap);
data->state.errorbuf = TRUE; /* wrote error string */ data->state.errorbuf = TRUE; /* wrote error string */
if(data->set.verbose) if(data->set.verbose) {
Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, int len = strlen(data->set.errorbuffer);
strlen(data->set.errorbuffer)); bool doneit=FALSE;
if(len < CURL_ERROR_SIZE) {
doneit = TRUE;
data->set.errorbuffer[len] = '\n';
data->set.errorbuffer[++len] = '\0';
}
Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len);
if(doneit)
/* cut off the newline again */
data->set.errorbuffer[--len]=0;
}
} }
va_end(ap); va_end(ap);
} }
@ -235,6 +245,9 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd,
/* this is basicly the EWOULDBLOCK equivalent */ /* this is basicly the EWOULDBLOCK equivalent */
*written = 0; *written = 0;
return CURLE_OK; return CURLE_OK;
case SSL_ERROR_SYSCALL:
failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n", errno);
return CURLE_SEND_ERROR;
} }
/* a true error */ /* a true error */
failf(conn->data, "SSL_write() return error %d\n", err); failf(conn->data, "SSL_write() return error %d\n", err);
@ -328,36 +341,29 @@ int Curl_read(struct connectdata *conn,
ssize_t *n) ssize_t *n)
{ {
ssize_t nread; ssize_t nread;
*n=0; /* reset amount to zero */
#ifdef USE_SSLEAY #ifdef USE_SSLEAY
if (conn->ssl.use) { if (conn->ssl.use) {
bool loop=TRUE; nread = SSL_read(conn->ssl.handle, buf, buffersize);
int err;
do {
nread = SSL_read(conn->ssl.handle, buf, buffersize);
if(nread >= 0) if(nread < 0) {
/* successful read */ /* failed SSL_read */
break; int err = SSL_get_error(conn->ssl.handle, nread);
err = SSL_get_error(conn->ssl.handle, nread);
switch(err) { switch(err) {
case SSL_ERROR_NONE: /* this is not an error */ case SSL_ERROR_NONE: /* this is not an error */
case SSL_ERROR_ZERO_RETURN: /* no more data */ case SSL_ERROR_ZERO_RETURN: /* no more data */
loop=0; /* get out of loop */
break; break;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
/* if there's data pending, then we re-invoke SSL_read() */ /* there's data pending, re-invoke SSL_read() */
break; return -1; /* basicly EWOULDBLOCK */
default: default:
failf(conn->data, "SSL read error: %d", err); failf(conn->data, "SSL read error: %d", err);
return CURLE_RECV_ERROR; return CURLE_RECV_ERROR;
} }
} while(loop); }
if(loop && SSL_pending(conn->ssl.handle))
return -1; /* basicly EWOULDBLOCK */
} }
else { else {
#endif #endif

View File

@ -30,13 +30,6 @@ void Curl_failf(struct SessionHandle *, const char *fmt, ...);
#define infof Curl_infof #define infof Curl_infof
#define failf Curl_failf #define failf Curl_failf
struct send_buffer {
char *buffer;
size_t size_max;
size_t size_used;
};
typedef struct send_buffer send_buffer;
#define CLIENTWRITE_BODY 1 #define CLIENTWRITE_BODY 1
#define CLIENTWRITE_HEADER 2 #define CLIENTWRITE_HEADER 2
#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER) #define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)

View File

@ -35,9 +35,8 @@
#define CURL_DISABLE_GOPHER #define CURL_DISABLE_GOPHER
#endif #endif
#if !defined(WIN32) && defined(_WIN32) #if !defined(WIN32) && defined(__WIN32__)
/* This _might_ be a good Borland fix. Please report whether this works or /* This should be a good Borland fix. Alexander J. Oss told us! */
not! */
#define WIN32 #define WIN32
#endif #endif

52
Source/CTest/Curl/share.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef __CURL_SHARE_H
#define __CURL_SHARE_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* 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 COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
***************************************************************************/
#include "setup.h"
#include <curl/curl.h>
/* this struct is libcurl-private, don't export details */
struct Curl_share {
unsigned int specifier;
unsigned int locked;
unsigned int dirty;
curl_lock_function lockfunc;
curl_unlock_function unlockfunc;
void *clientdata;
};
CURLSHcode Curl_share_aquire_lock (struct SessionHandle *, curl_lock_data);
CURLSHcode Curl_share_release_lock (struct SessionHandle *, curl_lock_data);
#endif /* __CURL_SHARE_H */
/*
* local variables:
* eval: (load-file "../curl-mode.el")
* end:
* vim600: fdm=marker
* vim: et sw=2 ts=2 sts=2 tw=78
*/

View File

@ -275,7 +275,8 @@ int cert_stuff(struct connectdata *conn,
if (SSL_CTX_use_PrivateKey_file(conn->ssl.ctx, if (SSL_CTX_use_PrivateKey_file(conn->ssl.ctx,
key_file, key_file,
file_type) != 1) { file_type) != 1) {
failf(data, "unable to set private key file\n"); failf(data, "unable to set private key file: '%s' type %s\n",
key_file, key_type?key_type:"PEM");
return 0; return 0;
} }
break; break;
@ -324,10 +325,15 @@ int cert_stuff(struct connectdata *conn,
ssl=SSL_new(conn->ssl.ctx); ssl=SSL_new(conn->ssl.ctx);
x509=SSL_get_certificate(ssl); x509=SSL_get_certificate(ssl);
if (x509 != NULL) /* This version was provided by Evan Jordan and is supposed to not
EVP_PKEY_copy_parameters(X509_get_pubkey(x509), leak memory as the previous version: */
SSL_get_privatekey(ssl)); if (x509 != NULL) {
EVP_PKEY *pktmp = X509_get_pubkey(x509);
EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl));
EVP_PKEY_free(pktmp);
}
SSL_free(ssl); SSL_free(ssl);
/* If we are using DSA, we can copy the parameters from /* If we are using DSA, we can copy the parameters from
@ -666,6 +672,44 @@ static int Curl_ASN1_UTCTIME_output(struct connectdata *conn,
#endif #endif
/* ====================================================== */
static int
cert_hostcheck(const char *certname, const char *hostname)
{
char *tmp;
const char *certdomain;
if(!certname ||
strlen(certname)<3 ||
!hostname ||
!strlen(hostname)) /* sanity check */
return 0;
if(strequal(certname, hostname)) /* trivial case */
return 1;
certdomain = certname + 1;
if((certname[0] != '*') || (certdomain[0] != '.'))
return 0; /* not a wildcard certificate, check failed */
if(!strchr(certdomain+1, '.'))
return 0; /* the certificate must have at least another dot in its name */
/* find 'certdomain' within 'hostname' */
tmp = strstr(hostname, certdomain);
if(tmp) {
/* ok the certname's domain matches the hostname, let's check that it's a
tail-match */
if(strequal(tmp, certdomain))
/* looks like a match. Just check we havent swallowed a '.' */
return tmp == strchr(hostname, '.');
else
return 0;
}
return 0;
}
/* ====================================================== */ /* ====================================================== */
CURLcode CURLcode
Curl_SSLConnect(struct connectdata *conn) Curl_SSLConnect(struct connectdata *conn)
@ -904,7 +948,7 @@ Curl_SSLConnect(struct connectdata *conn)
return CURLE_SSL_PEER_CERTIFICATE; return CURLE_SSL_PEER_CERTIFICATE;
} }
if (!strequal(peer_CN, conn->hostname)) { if (!cert_hostcheck(peer_CN, conn->hostname)) {
if (data->set.ssl.verifyhost > 1) { if (data->set.ssl.verifyhost > 1) {
failf(data, "SSL: certificate subject name '%s' does not match " failf(data, "SSL: certificate subject name '%s' does not match "
"target host name '%s'", "target host name '%s'",

File diff suppressed because it is too large Load Diff

View File

@ -101,6 +101,7 @@
#include "strequal.h" #include "strequal.h"
#include "escape.h" #include "escape.h"
#include "strtok.h" #include "strtok.h"
#include "share.h"
/* And now for the protocols */ /* And now for the protocols */
#include "ftp.h" #include "ftp.h"
@ -1071,8 +1072,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
case CURLOPT_SHARE: case CURLOPT_SHARE:
{ {
curl_share *set; struct Curl_share *set;
set = va_arg(param, curl_share *); set = va_arg(param, struct Curl_share *);
if(data->share) if(data->share)
data->share->dirty--; data->share->dirty--;
@ -1088,6 +1089,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
data->set.proxytype = va_arg(param, long); data->set.proxytype = va_arg(param, long);
break; break;
case CURLOPT_PRIVATE:
/*
* Set private data pointer.
*/
data->set.private = va_arg(param, char *);
break;
case CURLOPT_HTTP200ALIASES:
/*
* Set a list of aliases for HTTP 200 in response header
*/
data->set.http200aliases = va_arg(param, struct curl_slist *);
break;
default: default:
/* unknown tag and its companion, just ignore: */ /* unknown tag and its companion, just ignore: */
return CURLE_FAILED_INIT; /* correct this */ return CURLE_FAILED_INIT; /* correct this */
@ -1603,6 +1618,9 @@ static CURLcode ConnectPlease(struct connectdata *conn,
return result; return result;
} }
/*
* ALERT! The 'dns' pointer being passed in here might be NULL at times.
*/
static void verboseconnect(struct connectdata *conn, static void verboseconnect(struct connectdata *conn,
struct Curl_dns_entry *dns) struct Curl_dns_entry *dns)
{ {
@ -1667,6 +1685,12 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK; CURLcode result=CURLE_OK;
if(conn->bits.tcpconnect)
/* We already are connected, get back. This may happen when the connect
worked fine in the first call, like when we connect to a local server
or proxy. */
return CURLE_OK;
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
if(data->set.verbose) if(data->set.verbose)
@ -1779,6 +1803,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* else, no chunky upload */ /* else, no chunky upload */
FALSE; FALSE;
conn->fread = data->set.fread;
conn->fread_in = data->set.in;
/*********************************************************** /***********************************************************
* We need to allocate memory to store the path in. We get the size of the * 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 * full URL to be sure, and we need to make it at least 256 bytes since
@ -2286,6 +2313,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* Setup a "faked" transfer that'll do nothing */ /* Setup a "faked" transfer that'll do nothing */
if(CURLE_OK == result) { if(CURLE_OK == result) {
conn->bits.tcpconnect = TRUE; /* we are "connected */
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */ result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
-1, NULL); /* no upload */ -1, NULL); /* no upload */
} }
@ -2463,6 +2491,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* no name given, get the password only */ /* no name given, get the password only */
sscanf(userpass, ":%127[^@]", data->state.passwd); sscanf(userpass, ":%127[^@]", data->state.passwd);
/* we have set the password */
data->state.passwdgiven = TRUE;
if(data->state.user[0]) { if(data->state.user[0]) {
char *newname=curl_unescape(data->state.user, 0); char *newname=curl_unescape(data->state.user, 0);
if(strlen(newname) < sizeof(data->state.user)) { if(strlen(newname) < sizeof(data->state.user)) {
@ -2498,14 +2529,17 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* the name is given, get user+password */ /* the name is given, get user+password */
sscanf(data->set.userpwd, "%127[^:]:%127[^\n]", sscanf(data->set.userpwd, "%127[^:]:%127[^\n]",
data->state.user, data->state.passwd); data->state.user, data->state.passwd);
if(strchr(data->set.userpwd, ':'))
/* a colon means the password was given, even if blank */
data->state.passwdgiven = TRUE;
} }
else else
/* no name given, get the password only */ /* no name given, starts with a colon, get the password only */
sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd); sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd);
} }
if (data->set.use_netrc != CURL_NETRC_IGNORED && if (data->set.use_netrc != CURL_NETRC_IGNORED &&
data->state.passwd[0] == '\0' ) { /* need passwd */ !data->state.passwdgiven) { /* need passwd */
if(Curl_parsenetrc(conn->hostname, if(Curl_parsenetrc(conn->hostname,
data->state.user, data->state.user,
data->state.passwd)) { data->state.passwd)) {
@ -2516,8 +2550,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
} }
/* if we have a user but no password, ask for one */ /* if we have a user but no password, ask for one */
if(conn->bits.user_passwd && if(conn->bits.user_passwd && !data->state.passwdgiven ) {
!data->state.passwd[0] ) {
if(data->set.fpasswd(data->set.passwd_client, if(data->set.fpasswd(data->set.passwd_client,
"password:", data->state.passwd, "password:", data->state.passwd,
sizeof(data->state.passwd))) sizeof(data->state.passwd)))
@ -2528,9 +2561,12 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* If our protocol needs a password and we have none, use the defaults */ /* If our protocol needs a password and we have none, use the defaults */
if ( (conn->protocol & (PROT_FTP|PROT_HTTP)) && if ( (conn->protocol & (PROT_FTP|PROT_HTTP)) &&
!conn->bits.user_passwd) { !conn->bits.user_passwd &&
!data->state.passwdgiven) {
strcpy(data->state.user, CURL_DEFAULT_USER); strcpy(data->state.user, CURL_DEFAULT_USER);
strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD); strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD);
/* This is the default password, so DON'T set conn->bits.user_passwd */ /* This is the default password, so DON'T set conn->bits.user_passwd */
} }
@ -2782,14 +2818,21 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* Connect only if not already connected! */ /* Connect only if not already connected! */
result = ConnectPlease(conn, hostaddr, &connected); result = ConnectPlease(conn, hostaddr, &connected);
if(connected) if(connected) {
result = Curl_protocol_connect(conn, hostaddr); result = Curl_protocol_connect(conn, hostaddr);
if(CURLE_OK == result)
conn->bits.tcpconnect = TRUE;
}
else
conn->bits.tcpconnect = FALSE;
if(CURLE_OK != result) if(CURLE_OK != result)
return result; return result;
} }
else { else {
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
conn->bits.tcpconnect = TRUE;
if(data->set.verbose) if(data->set.verbose)
verboseconnect(conn, hostaddr); verboseconnect(conn, hostaddr);
} }

View File

@ -157,6 +157,8 @@ struct ssl_config_data {
struct HTTP { struct HTTP {
struct FormData *sendit; struct FormData *sendit;
int postsize; int postsize;
char *postdata;
const char *p_pragma; /* Pragma: string */ const char *p_pragma; /* Pragma: string */
const char *p_accept; /* Accept: string */ const char *p_accept; /* Accept: string */
long readbytecount; long readbytecount;
@ -164,10 +166,24 @@ struct HTTP {
/* For FORM posting */ /* For FORM posting */
struct Form form; struct Form form;
curl_read_callback storefread;
FILE *in;
struct Curl_chunker chunk; struct Curl_chunker chunk;
struct back {
curl_read_callback fread; /* backup storage for fread pointer */
void *fread_in; /* backup storage for fread_in pointer */
char *postdata;
int postsize;
} backup;
enum {
HTTPSEND_NADA, /* init */
HTTPSEND_REQUEST, /* sending a request */
HTTPSEND_BODY, /* sending body */
HTTPSEND_LAST /* never use this */
} sending;
void *send_buffer; /* used if the request couldn't be sent in one chunk,
points to an allocated send_buffer struct */
}; };
/**************************************************************************** /****************************************************************************
@ -190,7 +206,9 @@ struct FTP {
read the line, just ignore the result. */ read the line, just ignore the result. */
bool no_transfer; /* nothing was transfered, (possibly because a resumed bool no_transfer; /* nothing was transfered, (possibly because a resumed
transfer already was complete) */ transfer already was complete) */
long response_time; /* When no timeout is given, this is the amount of
seconds we await for an FTP response. Initialized
in Curl_ftp_connect() */
}; };
/**************************************************************************** /****************************************************************************
@ -220,8 +238,14 @@ struct ConnectBits {
bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding
on upload */ on upload */
bool getheader; /* TRUE if header parsing is wanted */
bool getheader; /* TRUE if header parsing is wanted */ bool forbidchunk; /* used only to explicitly forbid chunk-upload for
specific upload buffers. See readmoredata() in
http.c for details. */
bool tcpconnect; /* the tcp stream (or simimlar) is connected, this
is set the first time on the first connect function
call */
}; };
/* /*
@ -456,6 +480,9 @@ struct connectdata {
and the 'upload_present' contains the number of bytes available at this and the 'upload_present' contains the number of bytes available at this
position */ position */
char *upload_fromhere; char *upload_fromhere;
curl_read_callback fread; /* function that reads the input */
void *fread_in; /* pointer to pass to the fread() above */
}; };
/* The end of connectdata. 08/27/02 jhrg */ /* The end of connectdata. 08/27/02 jhrg */
@ -543,6 +570,9 @@ struct UrlState {
char proxyuser[MAX_CURL_USER_LENGTH]; char proxyuser[MAX_CURL_USER_LENGTH];
char proxypasswd[MAX_CURL_PASSWORD_LENGTH]; char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
bool passwdgiven; /* set TRUE if an application-provided password has been
set */
struct timeval keeps_speed; /* for the progress meter really */ struct timeval keeps_speed; /* for the progress meter really */
/* 'connects' will be an allocated array with pointers. If the pointer is /* 'connects' will be an allocated array with pointers. If the pointer is
@ -631,7 +661,7 @@ struct UserDefined {
bool free_referer; /* set TRUE if 'referer' points to a string we bool free_referer; /* set TRUE if 'referer' points to a string we
allocated */ allocated */
char *useragent; /* User-Agent string */ char *useragent; /* User-Agent string */
char *encoding; /* Accept-Encoding string 08/28/02 jhrg */ char *encoding; /* Accept-Encoding string */
char *postfields; /* if POST, set the fields' values here */ char *postfields; /* if POST, set the fields' values here */
size_t postfieldsize; /* if POST, this might have a size to use instead of size_t postfieldsize; /* if POST, this might have a size to use instead of
strlen(), and then the data *may* be binary (contain strlen(), and then the data *may* be binary (contain
@ -686,6 +716,10 @@ struct UserDefined {
int dns_cache_timeout; /* DNS cache timeout */ int dns_cache_timeout; /* DNS cache timeout */
long buffer_size; /* size of receive buffer to use */ long buffer_size; /* size of receive buffer to use */
char *private; /* Private data */
struct curl_slist *http200aliases; /* linked list of aliases for http200 */
/* Here follows boolean settings that define how to behave during /* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially this session. They are STATIC, set by libcurl users or at least initially
@ -734,7 +768,7 @@ struct UserDefined {
struct SessionHandle { struct SessionHandle {
curl_hash *hostcache; curl_hash *hostcache;
curl_share *share; /* Share, handles global variable mutexing */ struct Curl_share *share; /* Share, handles global variable mutexing */
struct UserDefined set; /* values set by the libcurl user */ struct UserDefined set; /* values set by the libcurl user */
struct DynamicStatic change; /* possibly modified userdefined data */ struct DynamicStatic change; /* possibly modified userdefined data */