From 96dde76b99897352aa3d0877a0b621a9e605733e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 22 May 2000 14:12:12 +0000 Subject: moved here from the newlib branch --- lib/url.c | 1005 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 483 insertions(+), 522 deletions(-) (limited to 'lib/url.c') diff --git a/lib/url.c b/lib/url.c index 75dd89559..5938c5771 100644 --- a/lib/url.c +++ b/lib/url.c @@ -38,11 +38,6 @@ * ------------------------------------------------------------ ****************************************************************************/ -/* - * SSL code intially written by - * Linas Vepstas and Sampo Kellomaki - */ - /* -- WIN32 approved -- */ #include #include @@ -116,6 +111,8 @@ #include "getpass.h" #include "progress.h" #include "cookie.h" +#include "strequal.h" +#include "writeout.h" /* And now for the protocols */ #include "ftp.h" @@ -124,81 +121,28 @@ #include "http.h" #include "file.h" #include "ldap.h" -#include "writeout.h" + +#include #define _MPRINTF_REPLACE /* use our functions only */ #include /* -- -- */ -/*********************************************************************** - * Start with some silly functions to make win32-systems survive - ***********************************************************************/ -#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) -static void win32_cleanup(void) -{ - WSACleanup(); -} - -static UrgError win32_init(void) -{ - WORD wVersionRequested; - WSADATA wsaData; - int err; - wVersionRequested = MAKEWORD(1, 1); - - err = WSAStartup(wVersionRequested, &wsaData); - - if (err != 0) - /* Tell the user that we couldn't find a useable */ - /* winsock.dll. */ - return URG_FAILED_INIT; - - /* Confirm that the Windows Sockets DLL supports 1.1.*/ - /* Note that if the DLL supports versions greater */ - /* than 1.1 in addition to 1.1, it will still return */ - /* 1.1 in wVersion since that is the version we */ - /* requested. */ - - if ( LOBYTE( wsaData.wVersion ) != 1 || - HIBYTE( wsaData.wVersion ) != 1 ) { - /* Tell the user that we couldn't find a useable */ - - /* winsock.dll. */ - WSACleanup(); - return URG_FAILED_INIT; - } - return URG_OK; -} -/* The Windows Sockets DLL is acceptable. Proceed. */ -#else -static UrgError win32_init(void) { return URG_OK; } -#define win32_cleanup() -#endif +CURLcode _urlget(struct UrlData *data); -/* - * This is the main global constructor for the lib. Call this before - * _any_ libcurl usage. If this fails, *NO* libcurl functions may be - * used, or havoc may be the result. - */ -UrgError curl_init(void) +/* does nothing, returns OK */ +CURLcode curl_init(void) { - return win32_init(); + return CURLE_OK; } -/* - * This is the main global destructor for the lib. Call this after - * _all_ libcurl usage is done. - */ +/* does nothing */ void curl_free(void) { - win32_cleanup(); } -static UrgError _urlget(struct UrlData *data); - - void urlfree(struct UrlData *data, bool totally) { #ifdef USE_SSLEAY @@ -278,27 +222,78 @@ void urlfree(struct UrlData *data, bool totally) } } -typedef struct UrlData CURL; +CURLcode curl_close(CURL *curl) +{ + struct UrlData *data=(struct UrlData *)curl; + + void *protocol = data->proto.generic; + + /* total session cleanup */ + urlfree(data, TRUE); + + if(protocol) + free(protocol); + + free(data); + + return CURLE_OK; +} -UrgError curl_open(CURL **curl, char *url) +CURLcode curl_open(CURL **curl, char *url) { /* We don't yet support specifying the URL at this point */ + struct UrlData *data; /* Very simple start-up: alloc the struct, init it with zeroes and return */ - CURL *data = (CURL *)malloc(sizeof(CURL)); + data = (struct UrlData *)malloc(sizeof(struct UrlData)); if(data) { - memset(data, 0, sizeof(CURL)); + memset(data, 0, sizeof(struct UrlData)); + data->handle = STRUCT_OPEN; + data->interface = CURLI_NORMAL; /* normal interface by default */ + + /* We do some initial setup here, all those fields that can't be just 0 */ + + data-> headerbuff=(char*)malloc(HEADERSIZE); + if(!data->headerbuff) { + free(data); /* free the memory again */ + return CURLE_OUT_OF_MEMORY; + } + + data-> headersize=HEADERSIZE; + +#if 0 + /* Let's set some default values: */ + curl_setopt(data, CURLOPT_FILE, stdout); /* default output to stdout */ + curl_setopt(data, CURLOPT_INFILE, stdin); /* default input from stdin */ + curl_setopt(data, CURLOPT_STDERR, stderr); /* default stderr to stderr! */ +#endif + + data->out = stdout; /* default output to stdout */ + data->in = stdin; /* default input from stdin */ + data->err = stderr; /* default stderr to stderr */ + + data->firstsocket = -1; /* no file descriptor */ + data->secondarysocket = -1; /* no file descriptor */ + + /* use fwrite as default function to store output */ + data->fwrite = (size_t (*)(char *, size_t, size_t, FILE *))fwrite; + + /* use fread as default function to read input */ + data->fread = (size_t (*)(char *, size_t, size_t, FILE *))fread; + + data->infilesize = -1; /* we don't know any size */ + + data->current_speed = -1; /* init to negative == impossible */ + *curl = data; - return URG_OK; + return CURLE_OK; } /* this is a very serious error */ - return URG_OUT_OF_MEMORY; + return CURLE_OUT_OF_MEMORY; } -typedef unsigned int CURLoption; - -UrgError curl_setopt(CURL *curl, CURLoption option, ...) +CURLcode curl_setopt(CURL *curl, CURLoption option, ...) { struct UrlData *data = curl; va_list param; @@ -307,310 +302,187 @@ UrgError curl_setopt(CURL *curl, CURLoption option, ...) va_start(param, option); switch(option) { - case URGTAG_TIMECONDITION: + case CURLOPT_VERBOSE: + data->bits.verbose = va_arg(param, long); + break; + case CURLOPT_HEADER: + data->bits.http_include_header = va_arg(param, long); + break; + case CURLOPT_NOPROGRESS: + data->bits.hide_progress = va_arg(param, long); + if(data->bits.hide_progress) + data->progress.flags |= PGRS_HIDE; + break; + case CURLOPT_NOBODY: + data->bits.no_body = va_arg(param, long); + break; + case CURLOPT_FAILONERROR: + data->bits.http_fail_on_error = va_arg(param, long); + break; + case CURLOPT_UPLOAD: + data->bits.upload = va_arg(param, long); + break; + case CURLOPT_POST: + data->bits.http_post = va_arg(param, long); + break; + case CURLOPT_FTPLISTONLY: + data->bits.ftp_list_only = va_arg(param, long); + break; + case CURLOPT_FTPAPPEND: + data->bits.ftp_append = va_arg(param, long); + break; + case CURLOPT_NETRC: + data->bits.use_netrc = va_arg(param, long); + break; + case CURLOPT_FOLLOWLOCATION: + data->bits.http_follow_location = va_arg(param, long); + break; + case CURLOPT_FTPASCII: + data->bits.ftp_ascii = va_arg(param, long); + break; + case CURLOPT_PUT: + data->bits.http_put = va_arg(param, long); + break; + case CURLOPT_MUTE: + data->bits.mute = va_arg(param, long); + break; + + case CURLOPT_TIMECONDITION: data->timecondition = va_arg(param, long); break; - case URGTAG_TIMEVALUE: + case CURLOPT_TIMEVALUE: data->timevalue = va_arg(param, long); break; - case URGTAG_SSLVERSION: + case CURLOPT_SSLVERSION: data->ssl_version = va_arg(param, long); break; - case URGTAG_COOKIEFILE: + case CURLOPT_COOKIEFILE: cookiefile = (char *)va_arg(param, void *); if(cookiefile) { data->cookies = cookie_init(cookiefile); } break; - case URGTAG_WRITEHEADER: + case CURLOPT_WRITEHEADER: data->writeheader = (FILE *)va_arg(param, FILE *); break; - case URGTAG_COOKIE: + case CURLOPT_COOKIE: data->cookie = va_arg(param, char *); break; - case URGTAG_ERRORBUFFER: + case CURLOPT_ERRORBUFFER: data->errorbuffer = va_arg(param, char *); break; - case URGTAG_FILE: + case CURLOPT_FILE: data->out = va_arg(param, FILE *); break; - case URGTAG_FTPPORT: + case CURLOPT_FTPPORT: data->ftpport = va_arg(param, char *); + data->bits.ftp_use_port = data->ftpport?1:0; break; - case URGTAG_HTTPHEADER: + case CURLOPT_HTTPHEADER: data->headers = va_arg(param, struct HttpHeader *); break; - case URGTAG_CUSTOMREQUEST: + case CURLOPT_CUSTOMREQUEST: data->customrequest = va_arg(param, char *); break; - case URGTAG_HTTPPOST: + case CURLOPT_HTTPPOST: data->httppost = va_arg(param, struct HttpPost *); + data->bits.http_formpost = data->httppost?1:0; break; - case URGTAG_INFILE: + case CURLOPT_INFILE: data->in = va_arg(param, FILE *); break; - case URGTAG_INFILESIZE: + case CURLOPT_INFILESIZE: data->infilesize = va_arg(param, long); break; - case URGTAG_LOW_SPEED_LIMIT: + case CURLOPT_LOW_SPEED_LIMIT: data->low_speed_limit=va_arg(param, long); break; - case URGTAG_LOW_SPEED_TIME: + case CURLOPT_LOW_SPEED_TIME: data->low_speed_time=va_arg(param, long); break; - case URGTAG_URL: + case CURLOPT_URL: data->url = va_arg(param, char *); break; - case URGTAG_PORT: + case CURLOPT_PORT: /* this typecast is used to fool the compiler to NOT warn for a "cast from pointer to integer of different size" */ data->port = (unsigned short)(va_arg(param, long)); break; - case URGTAG_POSTFIELDS: + case CURLOPT_POSTFIELDS: data->postfields = va_arg(param, char *); break; - case URGTAG_PROGRESSMODE: + case CURLOPT_PROGRESSMODE: data->progress.mode = va_arg(param, long); break; - case URGTAG_REFERER: + case CURLOPT_REFERER: data->referer = va_arg(param, char *); + data->bits.http_set_referer = (data->referer && *data->referer)?1:0; break; - case URGTAG_PROXY: + case CURLOPT_PROXY: data->proxy = va_arg(param, char *); + data->bits.httpproxy = data->proxy?1:0; break; - case URGTAG_FLAGS: - data->conf = va_arg(param, long); +#if 0 + case CURLOPT_FLAGS: + conf_to_internal(data, va_arg(param, long)); break; - case URGTAG_TIMEOUT: +#endif + case CURLOPT_TIMEOUT: data->timeout = va_arg(param, long); break; - case URGTAG_USERAGENT: + case CURLOPT_USERAGENT: data->useragent = va_arg(param, char *); break; - case URGTAG_USERPWD: + case CURLOPT_USERPWD: data->userpwd = va_arg(param, char *); + data->bits.user_passwd = data->userpwd?1:0; break; - case URGTAG_POSTQUOTE: + case CURLOPT_POSTQUOTE: data->postquote = va_arg(param, struct curl_slist *); break; - case URGTAG_PROXYUSERPWD: + case CURLOPT_PROXYUSERPWD: data->proxyuserpwd = va_arg(param, char *); + data->bits.proxy_user_passwd = data->proxyuserpwd?1:0; break; - case URGTAG_RANGE: + case CURLOPT_RANGE: data->range = va_arg(param, char *); + data->bits.set_range = data->range?1:0; break; - case URGTAG_RESUME_FROM: + case CURLOPT_RESUME_FROM: data->resume_from = va_arg(param, long); break; - case URGTAG_STDERR: + case CURLOPT_STDERR: data->err = va_arg(param, FILE *); break; - case URGTAG_WRITEFUNCTION: - data->fwrite = va_arg(param, void *); + case CURLOPT_WRITEFUNCTION: + data->fwrite = va_arg(param, write_callback); break; - case URGTAG_WRITEINFO: + case CURLOPT_WRITEINFO: data->writeinfo = va_arg(param, char *); break; - case URGTAG_READFUNCTION: - data->fread = va_arg(param, void *); + case CURLOPT_READFUNCTION: + data->fread = va_arg(param, read_callback); break; - case URGTAG_SSLCERT: + case CURLOPT_SSLCERT: data->cert = va_arg(param, char *); break; - case URGTAG_SSLCERTPASSWD: + case CURLOPT_SSLCERTPASSWD: data->cert_passwd = va_arg(param, char *); break; - case URGTAG_CRLF: + case CURLOPT_CRLF: data->crlf = va_arg(param, long); break; - case URGTAG_QUOTE: + case CURLOPT_QUOTE: data->quote = va_arg(param, struct curl_slist *); break; default: /* unknown tag and its companion, just ignore: */ - return URG_READ_ERROR; /* correct this */ - } - return URG_OK; -} - - -typedef int (*func_T)(void); - -UrgError curl_urlget(UrgTag tag, ...) -{ - va_list arg; - func_T param_func = (func_T)0; - long param_long = 0; - void *param_obj = NULL; - UrgError res; - - struct UrlData *data; - - /* this is for the lame win32 socket crap */ - if(curl_init()) - return URG_FAILED_INIT; - - /* We use curl_open() with undefined URL so far */ - res = curl_open(&data, NULL); - if(res == URG_OK) { - /* data is now filled with good-looking zeroes */ - - /* Let's set some default values: */ - curl_setopt(data, URGTAG_FILE, stdout); /* default output to stdout */ - curl_setopt(data, URGTAG_INFILE, stdin); /* default input from stdin */ - curl_setopt(data, URGTAG_STDERR, stderr); /* default stderr to stderr! */ - - data->firstsocket = -1; /* no file descriptor */ - data->secondarysocket = -1; /* no file descriptor */ - - /* use fwrite as default function to store output */ - data->fwrite = (size_t (*)(char *, size_t, size_t, FILE *))fwrite; - - /* use fread as default function to read input */ - data->fread = (size_t (*)(char *, size_t, size_t, FILE *))fread; - - data->infilesize = -1; /* we don't know any size */ - - data->current_speed = -1; /* init to negative == impossible */ - - va_start(arg, tag); - - while(tag != URGTAG_DONE) { - /* PORTING NOTE: - Ojbect pointers can't necessarily be casted to function pointers and - therefore we need to know what type it is and read the correct type - at once. This should also correct problems with different sizes of - the types. - */ - - if(tag < URGTYPE_OBJECTPOINT) { - /* This is a LONG type */ - param_long = va_arg(arg, long); - curl_setopt(data, tag, param_long); - } - else if(tag < URGTYPE_FUNCTIONPOINT) { - /* This is a object pointer type */ - param_obj = va_arg(arg, void *); - curl_setopt(data, tag, param_obj); - } - else { - param_func = va_arg(arg, func_T ); - curl_setopt(data, tag, param_func); - } - - /* printf("tag: %d\n", tag); */ - tag = va_arg(arg, UrgTag); - } - - va_end(arg); - - pgrsMode(data, data->progress.mode); - pgrsStartNow(data); - - data-> headerbuff=(char*)malloc(HEADERSIZE); - if(!data->headerbuff) - return URG_FAILED_INIT; - - data-> headersize=HEADERSIZE; - - res = _urlget(data); /* fetch the URL please */ - - while((res == URG_OK) && data->newurl) { - /* Location: redirect */ - char prot[16]; - char path[URL_MAX_LENGTH]; - - if(2 != sscanf(data->newurl, "%15[^:]://%" URL_MAX_LENGTH_TXT - "s", prot, path)) { - /*** - *DANG* this is an RFC 2068 violation. The URL is supposed - to be absolute and this doesn't seem to be that! - *** - Instead, we have to TRY to append this new path to the old URL - to the right of the host part. Oh crap, this is doomed to cause - problems in the future... - */ - char *protsep; - char *pathsep; - char *newest; - - /* protsep points to the start of the host name */ - protsep=strstr(data->url, "//"); - if(!protsep) - protsep=data->url; - else { - data->port=0; /* we got a full URL and then we should reset the - port number here to re-initiate it later */ - protsep+=2; /* pass the // */ - } - - if('/' != data->newurl[0]) { - /* First we need to find out if there's a ?-letter in the URL, and - cut it and the right-side of that off */ - pathsep = strrchr(protsep, '?'); - if(pathsep) - *pathsep=0; - - /* we have a relative path to append to the last slash if - there's one available */ - pathsep = strrchr(protsep, '/'); - if(pathsep) - *pathsep=0; - } - else { - /* We got a new absolute path for this server, cut off from the - first slash */ - pathsep = strchr(protsep, '/'); - if(pathsep) - *pathsep=0; - } - - newest=(char *)malloc( strlen(data->url) + - 1 + /* possible slash */ - strlen(data->newurl) + 1/* zero byte */); - - if(!newest) - return URG_OUT_OF_MEMORY; - sprintf(newest, "%s%s%s", data->url, ('/' == data->newurl[0])?"":"/", - data->newurl); - free(data->newurl); - data->newurl = newest; - } - else { - /* This was an absolute URL, clear the port number! */ - data->port = 0; - } - - data->url = data->newurl; - data->newurl = NULL; /* don't show! */ - - infof(data, "Follows Location: to new URL: '%s'\n", data->url); - - /* clean up the sockets and SSL stuff from the previous "round" */ - urlfree(data, FALSE); - - res = _urlget(data); - } - if(data->newurl) - free(data->newurl); - + return CURLE_READ_ERROR; /* correct this */ } - else - res = URG_FAILED_INIT; /* failed */ - - if((URG_OK == res) && data->writeinfo) { - /* Time to output some info to stdout */ - WriteOut(data); - } - - - /* total cleanup */ - urlfree(data, TRUE); - - return res; + return CURLE_OK; } @@ -618,8 +490,7 @@ UrgError curl_urlget(UrgTag tag, ...) * Read everything until a newline. */ -static int GetLine(int sockfd, char *buf, - struct UrlData *data) +int GetLine(int sockfd, char *buf, struct UrlData *data) { int nread; int read_rc=1; @@ -645,7 +516,7 @@ static int GetLine(int sockfd, char *buf, } *ptr=0; /* zero terminate */ - if(data->conf & CONF_VERBOSE) { + if(data->bits.verbose) { fputs("< ", data->err); fwrite(buf, 1, nread, data->err); fputs("\n", data->err); @@ -654,7 +525,6 @@ static int GetLine(int sockfd, char *buf, } - #ifndef WIN32 #ifndef RETSIGTYPE #define RETSIGTYPE void @@ -667,35 +537,114 @@ RETSIGTYPE alarmfunc(int signal) } #endif -/* ====================================================== */ +CURLcode curl_write(CURLconnect *c_conn, char *buf, size_t amount, + size_t *n) +{ + struct connectdata *conn = (struct connectdata *)c_conn; + struct UrlData *data; + size_t bytes_written; + + if(!n || !conn || (conn->handle != STRUCT_CONNECT)) + return CURLE_FAILED_INIT; + data = conn->data; + +#ifdef USE_SSLEAY + if (data->use_ssl) { + bytes_written = SSL_write(data->ssl, buf, amount); + } + else { +#endif + bytes_written = swrite(conn->writesockfd, buf, amount); +#ifdef USE_SSLEAY + } +#endif /* USE_SSLEAY */ + + *n = bytes_written; + return CURLE_OK; +} + +CURLcode curl_read(CURLconnect *c_conn, char *buf, size_t buffersize, + size_t *n) +{ + struct connectdata *conn = (struct connectdata *)c_conn; + struct UrlData *data; + size_t nread; + + if(!n || !conn || (conn->handle != STRUCT_CONNECT)) + return CURLE_FAILED_INIT; + data = conn->data; + +#ifdef USE_SSLEAY + if (data->use_ssl) { + nread = SSL_read (data->ssl, buf, buffersize); + } + else { +#endif + nread = sread (conn->sockfd, buf, buffersize); +#ifdef USE_SSLEAY + } +#endif /* USE_SSLEAY */ + *n = nread; + return CURLE_OK; +} + +CURLcode curl_disconnect(CURLconnect *c_connect) +{ + struct connectdata *conn = c_connect; + + struct UrlData *data = conn->data; + + /* clean up the sockets and SSL stuff from the previous "round" */ + urlfree(data, FALSE); + + return CURLE_OK; +} + /* - * urlget - * (result put on stdout) + * NAME curl_connect() * - * ::= "://" [ ":" ] "/" + * DESCRIPTION * - * = "HTTP" | "HTTPS" | "GOPHER" | "FTP" + * Connects to the peer server and performs the initial setup. This function + * writes a connect handle to its second argument that is a unique handle for + * this connect. This allows multiple connects from the same handle returned + * by curl_open(). * - * When FTP: + * EXAMPLE * - * ::= [ ":" "@" ] + * CURLCode result; + * CURL curl; + * CURLconnect connect; + * result = curl_connect(curl, &connect); */ -static UrgError _urlget(struct UrlData *data) +CURLcode curl_connect(CURL *curl, CURLconnect **in_connect) { - struct hostent *hp=NULL; - struct sockaddr_in serv_addr; + char *tmp; char *buf; - char proto[64]; - char gname[256]="default.com"; - char *name; - char path[URL_MAX_LENGTH]="/"; - char *ppath, *tmp; - long bytecount; - struct timeval now; - - UrgError result; + CURLcode result; char resumerange[12]=""; + struct UrlData *data = curl; + struct connectdata *conn; + + if(!data || (data->handle != STRUCT_OPEN)) + return CURLE_BAD_FUNCTION_ARGUMENT; /* TBD: make error codes */ + + if(!data->url) + return CURLE_URL_MALFORMAT; + + conn = (struct connectdata *)malloc(sizeof(struct connectdata)); + if(!conn) { + *in_connect = NULL; /* clear the pointer */ + return CURLE_OUT_OF_MEMORY; + } + *in_connect = conn; + + memset(conn, 0, sizeof(struct connectdata)); + conn->handle = STRUCT_CONNECT; + + conn->data = data; /* remember our daddy */ + conn->state = CONN_INIT; buf = data->buffer; /* this is our buffer */ @@ -709,59 +658,60 @@ static UrgError _urlget(struct UrlData *data) * to SSL connect through the proxy -- and we don't know if we * will need to use SSL until we parse the url ... */ - if((1 == sscanf(data->url, "file://%" URL_MAX_LENGTH_TXT "[^\n]", - path))) { + if((2 == sscanf(data->url, "%64[^:]://%" URL_MAX_LENGTH_TXT "[^\n]", + conn->proto, + conn->path)) && strequal(conn->proto, "file")) { /* we deal with file:/// differently since it supports no hostname other than "localhost" and "127.0.0.1", - which ist unique among the protocols specified in RFC 1738 */ - if (strstr(path, "localhost/") || strstr(path, "127.0.0.1/")) - strcpy(path, &path[10]); /* ... since coincidentally - both host strings are of - equal length */ - /* otherwise, / is quietly ommitted */ - - - /* that's it, no more fiddling with proxies, redirections, - or SSL for files, go directly to the file reading function */ - result = file(data, path, &bytecount); - if(result) - return result; - - return URG_OK; + which is unique among the protocols specified in RFC 1738 */ + if (strnequal(conn->path, "localhost/", 10) || + strnequal(conn->path, "127.0.0.1/", 10)) + /* ... since coincidentally both host strings are of equal length + otherwise, / is quietly ommitted */ + strcpy(conn->path, &conn->path[10]); + + strcpy(conn->proto, "file"); } - else if (2 > sscanf(data->url, "%64[^\n:]://%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", - proto, gname, path)) { - + else { + /* Set default host and default path */ + strcpy(conn->gname, "curl.haxx.nu"); + strcpy(conn->path, "/"); + + if (2 > sscanf(data->url, + "%64[^\n:]://%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", + conn->proto, conn->gname, conn->path)) { - /* badly formatted, let's try the browser-style _without_ 'http://' */ - if((1 > sscanf(data->url, "%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", gname, - path)) ) { - failf(data, " malformed"); - return URG_URL_MALFORMAT; - } - if(strnequal(gname, "FTP", 3)) { - strcpy(proto, "ftp"); - } - else if(strnequal(gname, "GOPHER", 6)) - strcpy(proto, "gopher"); + /* badly formatted, let's try the browser-style _without_ 'http://' */ + if((1 > sscanf(data->url, "%256[^\n/]%" URL_MAX_LENGTH_TXT "[^\n]", + conn->gname, conn->path)) ) { + failf(data, " malformed"); + return CURLE_URL_MALFORMAT; + } + if(strnequal(conn->gname, "FTP", 3)) { + strcpy(conn->proto, "ftp"); + } + else if(strnequal(conn->gname, "GOPHER", 6)) + strcpy(conn->proto, "gopher"); #ifdef USE_SSLEAY - else if(strnequal(gname, "HTTPS", 5)) - strcpy(proto, "https"); + else if(strnequal(conn->gname, "HTTPS", 5)) + strcpy(conn->proto, "https"); #endif /* USE_SSLEAY */ - else if(strnequal(gname, "TELNET", 6)) - strcpy(proto, "telnet"); - else if (strnequal(gname, "DICT", sizeof("DICT")-1)) - strcpy(proto, "DICT"); - else if (strnequal(gname, "LDAP", sizeof("LDAP")-1)) - strcpy(proto, "LDAP"); - else - strcpy(proto, "http"); - - data->conf |= CONF_NOPROT; + else if(strnequal(conn->gname, "TELNET", 6)) + strcpy(conn->proto, "telnet"); + else if (strnequal(conn->gname, "DICT", sizeof("DICT")-1)) + strcpy(conn->proto, "DICT"); + else if (strnequal(conn->gname, "LDAP", sizeof("LDAP")-1)) + strcpy(conn->proto, "LDAP"); + else { + strcpy(conn->proto, "http"); + } + + conn->protocol |= PROT_MISSING; /* not given in URL */ + } } - if((data->conf & CONF_USERPWD) && ! (data->conf & CONF_NETRC)) { + if(data->bits.user_passwd && !data->bits.use_netrc) { if(':' != *data->userpwd) { if((1 <= sscanf(data->userpwd, "%127[^:]:%127s", data->user, data->passwd))) { @@ -774,11 +724,11 @@ static UrgError _urlget(struct UrlData *data) } if(!data->user[0]) { failf(data, "USER malformat: user name can't be zero length"); - return URG_MALFORMAT_USER; + return CURLE_MALFORMAT_USER; } } - if(data->conf & CONF_PROXYUSERPWD) { + if(data->bits.proxy_user_passwd) { if(':' != *data->proxyuserpwd) { if((1 <= sscanf(data->proxyuserpwd, "%127[^:]:%127s", data->proxyuser, data->proxypasswd))) { @@ -791,16 +741,16 @@ static UrgError _urlget(struct UrlData *data) } if(!data->proxyuser[0]) { failf(data, " Proxy USER malformat: user name can't be zero length"); - return URG_MALFORMAT_USER; + return CURLE_MALFORMAT_USER; } } - name = gname; - ppath = path; - data->hostname = name; + conn->name = conn->gname; + conn->ppath = conn->path; + data->hostname = conn->name; - if(!(data->conf & CONF_PROXY)) { + if(!data->bits.httpproxy) { /* If proxy was not specified, we check for default proxy environment variables, to enable i.e Lynx compliance: @@ -824,9 +774,9 @@ static UrgError _urlget(struct UrlData *data) nope=no_proxy?strtok(no_proxy, ", "):NULL; while(nope) { - if(strlen(nope) <= strlen(name)) { + if(strlen(nope) <= strlen(conn->name)) { char *checkn= - name + strlen(name) - strlen(nope); + conn->name + strlen(conn->name) - strlen(nope); if(strnequal(nope, checkn, strlen(nope))) { /* no proxy for this host! */ break; @@ -836,7 +786,7 @@ static UrgError _urlget(struct UrlData *data) } if(!nope) { /* It was not listed as without proxy */ - char *protop = proto; + char *protop = conn->proto; char *envp = proxy_env; char *prox; @@ -861,29 +811,29 @@ static UrgError _urlget(struct UrlData *data) if(proxy && *proxy) { /* we have a proxy here to set */ data->proxy = proxy; - data->conf |= CONF_PROXY; + data->bits.httpproxy=1; } } /* if (!nope) - it wasn't specfied non-proxy */ } /* NO_PROXY wasn't specified or '*' */ } /* if not using proxy */ - if((data->conf & (CONF_PROXY|CONF_NOPROT)) == (CONF_PROXY|CONF_NOPROT) ) { + if((conn->protocol&PROT_MISSING) && data->bits.httpproxy ) { /* We're guessing prefixes here and since we're told to use a proxy, we need to add the protocol prefix to the URL string before we continue! */ char *reurl; - reurl = maprintf("%s://%s", proto, data->url); + reurl = maprintf("%s://%s", conn->proto, data->url); if(!reurl) - return URG_OUT_OF_MEMORY; + return CURLE_OUT_OF_MEMORY; data->url = reurl; if(data->freethis) free(data->freethis); data->freethis = reurl; - data->conf &= ~CONF_NOPROT; /* switch that one off again */ + conn->protocol &= ~PROT_MISSING; /* switch that one off again */ } /* RESUME on a HTTP page is a tricky business. First, let's just check that @@ -894,11 +844,11 @@ static UrgError _urlget(struct UrlData *data) server, we just fail since we can't rewind the file writing from within this function. */ if(data->resume_from) { - if(!(data->conf & CONF_RANGE)) { + if(!data->bits.set_range) { /* if it already was in use, we just skip this */ sprintf(resumerange, "%d-", data->resume_from); data->range=resumerange; /* tell ourselves to fetch this range */ - data->conf |= CONF_RANGE; /* switch on range usage */ + data->bits.set_range = 1; /* switch on range usage */ } } @@ -916,50 +866,69 @@ static UrgError _urlget(struct UrlData *data) * works differently, depending on whether its SSL or not). */ - if (strequal(proto, "HTTP")) { + if (strequal(conn->proto, "HTTP")) { if(!data->port) data->port = PORT_HTTP; data->remote_port = PORT_HTTP; - data->conf |= CONF_HTTP; + conn->protocol |= PROT_HTTP; + conn->curl_do = http; + conn->curl_done = http_done; } - else if (strequal(proto, "HTTPS")) { + else if (strequal(conn->proto, "HTTPS")) { #ifdef USE_SSLEAY if(!data->port) data->port = PORT_HTTPS; data->remote_port = PORT_HTTPS; - data->conf |= CONF_HTTP; - data->conf |= CONF_HTTPS; + conn->protocol |= PROT_HTTP; + conn->protocol |= PROT_HTTPS; + + conn->curl_do = http; + conn->curl_done = http_done; + conn->curl_connect = http_connect; + #else /* USE_SSLEAY */ failf(data, "SSL is disabled, https: not supported!"); - return URG_UNSUPPORTED_PROTOCOL; + return CURLE_UNSUPPORTED_PROTOCOL; #endif /* !USE_SSLEAY */ } - else if (strequal(proto, "GOPHER")) { + else if (strequal(conn->proto, "GOPHER")) { if(!data->port) data->port = PORT_GOPHER; data->remote_port = PORT_GOPHER; /* Skip // in path if present */ - if (isdigit((int)path[1])) { - ppath = strchr(&path[1], '/'); - if (ppath == NULL) - ppath = path; + if (isdigit((int)conn->path[1])) { + conn->ppath = strchr(&conn->path[1], '/'); + if (conn->ppath == NULL) + conn->ppath = conn->path; } - data->conf |= CONF_GOPHER; + conn->protocol |= PROT_GOPHER; + conn->curl_do = http; + conn->curl_done = http_done; } - else if(strequal(proto, "FTP")) { + else if(strequal(conn->proto, "FTP")) { char *type; if(!data->port) data->port = PORT_FTP; data->remote_port = PORT_FTP; - data->conf |= CONF_FTP; + conn->protocol |= PROT_FTP; - ppath++; /* don't include the initial slash */ + if(data->bits.httpproxy) { + conn->curl_do = http; + conn->curl_done = http_done; + } + else { + conn->curl_do = ftp; + conn->curl_done = ftp_done; + conn->curl_connect = ftp_connect; + } + + conn->ppath++; /* don't include the initial slash */ /* FTP URLs support an extension like ";type=" that we'll try to get now! */ - type=strstr(ppath, ";type="); + type=strstr(conn->ppath, ";type="); if(!type) { - type=strstr(gname, ";type="); + type=strstr(conn->gname, ";type="); } if(type) { char command; @@ -967,54 +936,59 @@ static UrgError _urlget(struct UrlData *data) command = toupper(type[6]); switch(command) { case 'A': /* ASCII mode */ - data->conf |= CONF_FTPASCII; + data->bits.ftp_ascii = 1; break; case 'D': /* directory mode */ - data->conf |= CONF_FTPLISTONLY; + data->bits.ftp_list_only = 1; break; case 'I': /* binary mode */ default: /* switch off ASCII */ - data->conf &= ~CONF_FTPASCII; + data->bits.ftp_ascii = 0; break; } } } - else if(strequal(proto, "TELNET")) { + else if(strequal(conn->proto, "TELNET")) { /* telnet testing factory */ - data->conf |= CONF_TELNET; + conn->protocol |= PROT_TELNET; if(!data->port) data->port = PORT_TELNET; data->remote_port = PORT_TELNET; + + conn->curl_do = telnet; + conn->curl_done = telnet_done; + } - else if (strequal(proto, "DICT")) { - data->conf |= CONF_DICT; + else if (strequal(conn->proto, "DICT")) { + conn->protocol |= PROT_DICT; if(!data->port) data->port = PORT_DICT; data->remote_port = PORT_DICT; + conn->curl_do = dict; + conn->curl_done = dict_done; } - else if (strequal(proto, "LDAP")) { - data->conf |= CONF_LDAP; + else if (strequal(conn->proto, "LDAP")) { + conn->protocol |= PROT_LDAP; if(!data->port) data->port = PORT_LDAP; data->remote_port = PORT_LDAP; + conn->curl_do = ldap; + conn->curl_done = ldap_done; } - /* file:// is handled above */ - /* else if (strequal(proto, "FILE")) { - data->conf |= CONF_FILE; + else if (strequal(conn->proto, "FILE")) { + conn->protocol |= PROT_FILE; - result = file(data, path, &bytecount); - if(result) - return result; + conn->curl_do = file; + /* no done() function */ + } - return URG_OK; - }*/ else { - failf(data, "Unsupported protocol: %s", proto); - return URG_UNSUPPORTED_PROTOCOL; + failf(data, "Unsupported protocol: %s", conn->proto); + return CURLE_UNSUPPORTED_PROTOCOL; } - if(data->conf & CONF_NETRC) { + if(data->bits.use_netrc) { if(ParseNetrc(data->hostname, data->user, data->passwd)) { infof(data, "Couldn't find host %s in the .netrc file, using defaults", data->hostname); @@ -1025,25 +999,26 @@ static UrgError _urlget(struct UrlData *data) strcpy(data->user, CURL_DEFAULT_USER); if(!data->passwd[0]) strcpy(data->passwd, CURL_DEFAULT_PASSWORD); - if(data->conf & CONF_HTTP) { - data->conf |= CONF_USERPWD; + if(conn->protocol&PROT_HTTP) { + data->bits.user_passwd = 1; /* enable user+password */ } } - else if(!(data->conf & CONF_USERPWD) && - (data->conf & (CONF_FTP|CONF_HTTP)) ) { + else if(!(data->bits.user_passwd) && + (conn->protocol & (PROT_FTP|PROT_HTTP)) ) { /* This is a FTP or HTTP URL, and we haven't got the user+password in the extra parameter, we will now try to extract the possible user+password pair in a string like: ftp://user:password@ftp.my.site:8021/README */ char *ptr=NULL; /* assign to remove possible warnings */ - if(':' == *name) { + if(':' == *conn->name) { failf(data, "URL malformat: user can't be zero length"); - return URG_URL_MALFORMAT_USER; + return CURLE_URL_MALFORMAT_USER; } - if((1 <= sscanf(name, "%127[^:]:%127[^@]", - data->user, data->passwd)) && (ptr=strchr(name, '@'))) { - name = ++ptr; - data->conf |= CONF_USERPWD; + if((1 <= sscanf(conn->name, "%127[^:]:%127[^@]", + data->user, data->passwd)) && + (ptr=strchr(conn->name, '@'))) { + conn->name = ++ptr; + data->bits.user_passwd=1; /* enable user+password */ } else { strcpy(data->user, CURL_DEFAULT_USER); @@ -1051,19 +1026,19 @@ static UrgError _urlget(struct UrlData *data) } } - if(!(data->conf & CONF_PROXY)) { + if(!data->bits.httpproxy) { /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ - tmp = strchr(name, ':'); + tmp = strchr(conn->name, ':'); if (tmp) { *tmp++ = '\0'; data->port = atoi(tmp); } /* Connect to target host right on */ - if(!(hp = GetHost(data, name))) { - failf(data, "Couldn't resolv host '%s'", name); - return URG_COULDNT_RESOLVE_HOST; + if(!(conn->hp = GetHost(data, conn->name))) { + failf(data, "Couldn't resolv host '%s'", conn->name); + return CURLE_COULDNT_RESOLVE_HOST; } } else { @@ -1079,12 +1054,12 @@ static UrgError _urlget(struct UrlData *data) if(NULL == proxydup) { failf(data, "memory shortage"); - return URG_OUT_OF_MEMORY; + return CURLE_OUT_OF_MEMORY; } /* we use proxy all right, but we wanna know the remote port for SSL reasons */ - tmp = strchr(name, ':'); + tmp = strchr(conn->name, ':'); if (tmp) { *tmp++ = '\0'; /* cut off the name there */ data->remote_port = atoi(tmp); @@ -1111,9 +1086,9 @@ static UrgError _urlget(struct UrlData *data) } /* connect to proxy */ - if(!(hp = GetHost(data, proxyptr))) { + if(!(conn->hp = GetHost(data, proxyptr))) { failf(data, "Couldn't resolv proxy '%s'", proxyptr); - return URG_COULDNT_RESOLVE_PROXY; + return CURLE_COULDNT_RESOLVE_PROXY; } free(proxydup); /* free the duplicate pointer and not the modified */ @@ -1122,14 +1097,16 @@ static UrgError _urlget(struct UrlData *data) data->firstsocket = socket(AF_INET, SOCK_STREAM, 0); - memset((char *) &serv_addr, '\0', sizeof(serv_addr)); - memcpy((char *)&(serv_addr.sin_addr), hp->h_addr, hp->h_length); - serv_addr.sin_family = hp->h_addrtype; - - serv_addr.sin_port = htons(data->port); + memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr)); + memcpy((char *)&(conn->serv_addr.sin_addr), + conn->hp->h_addr, conn->hp->h_length); + conn->serv_addr.sin_family = conn->hp->h_addrtype; + conn->serv_addr.sin_port = htons(data->port); - if (connect(data->firstsocket, (struct sockaddr *) &serv_addr, - sizeof(serv_addr)) < 0) { + if (connect(data->firstsocket, + (struct sockaddr *) &(conn->serv_addr), + sizeof(conn->serv_addr) + ) < 0) { switch(errno) { #ifdef ECONNREFUSED /* this should be made nicer */ @@ -1146,10 +1123,10 @@ static UrgError _urlget(struct UrlData *data) failf(data, "Can't connect to server: %d", errno); break; } - return URG_COULDNT_CONNECT; + return CURLE_COULDNT_CONNECT; } - if(data->conf & CONF_PROXYUSERPWD) { + if(data->bits.proxy_user_passwd) { char authorization[512]; sprintf(data->buffer, "%s:%s", data->proxyuser, data->proxypasswd); base64Encode(data->buffer, authorization); @@ -1157,74 +1134,27 @@ static UrgError _urlget(struct UrlData *data) data->ptr_proxyuserpwd = maprintf("Proxy-authorization: Basic %s\015\012", authorization); } - if(data->conf & (CONF_HTTPS|CONF_HTTP|CONF_PROXY)) { + if((conn->protocol&PROT_HTTP) || data->bits.httpproxy) { if(data->useragent) { data->ptr_uagent = maprintf("User-Agent: %s\015\012", data->useragent); } } - - /* If we are not using a proxy and we want a secure connection, - * perform SSL initialization & connection now. - * If using a proxy with https, then we must tell the proxy to CONNECT - * us to the host we want to talk to. Only after the connect - * has occured, can we start talking SSL - */ - if (data->conf & CONF_HTTPS) { - if (data->conf & CONF_PROXY) { - - /* OK, now send the connect statment */ - sendf(data->firstsocket, data, - "CONNECT %s:%d HTTP/1.0\015\012" - "%s" - "%s" - "\r\n", - data->hostname, data->remote_port, - (data->conf&CONF_PROXYUSERPWD)?data->ptr_proxyuserpwd:"", - (data->useragent?data->ptr_uagent:"") - ); - - /* wait for the proxy to send us a HTTP/1.0 200 OK header */ - /* Daniel rewrote this part Nov 5 1998 to make it more obvious */ - { - int httperror=0; - int subversion=0; - while(GetLine(data->firstsocket, data->buffer, data)) { - if('\r' == data->buffer[0]) - break; /* end of headers */ - if(2 == sscanf(data->buffer, "HTTP/1.%d %d", - &subversion, - &httperror)) { - ; - } - } - if(200 != httperror) { - if(407 == httperror) - /* Added Nov 6 1998 */ - failf(data, "Proxy requires authorization!"); - else - failf(data, "Received error code %d from proxy", httperror); - return URG_READ_ERROR; - } - } - infof (data, "Proxy has replied to CONNECT request\n"); - } - - /* now, perform the SSL initialization for this socket */ - if(UrgSSLConnect (data)) { - return URG_SSL_CONNECT_ERROR; - } + if(conn->curl_connect) { + /* is there a post-connect() procedure? */ + result = conn->curl_connect(conn); } + pgrsTime(data, TIMER_CONNECT); - now = tvnow(); /* time this *after* the connect is done */ - bytecount = 0; + conn->now = tvnow(); /* time this *after* the connect is done */ + conn->bytecount = 0; /* Figure out the ip-number and the first host name it shows: */ { struct in_addr in; - (void) memcpy(&in.s_addr, *hp->h_addr_list, sizeof (in.s_addr)); - infof(data, "Connected to %s (%s)\n", hp->h_name, inet_ntoa(in)); + (void) memcpy(&in.s_addr, *conn->hp->h_addr_list, sizeof (in.s_addr)); + infof(data, "Connected to %s (%s)\n", conn->hp->h_name, inet_ntoa(in)); } #if 0 /* Kerberos experiements! Beware! Take cover! */ @@ -1243,36 +1173,67 @@ static UrgError _urlget(struct UrlData *data) } #endif - if((data->conf&(CONF_FTP|CONF_PROXY)) == CONF_FTP) { - result = ftp(data, &bytecount, data->user, data->passwd, ppath); - if(result) - return result; + return CURLE_OK; +} + +CURLcode curl_done(CURLconnect *c_connect) +{ + struct connectdata *conn = c_connect; + struct UrlData *data; + CURLcode result; + + if(!conn || (conn->handle!= STRUCT_CONNECT)) { + return CURLE_BAD_FUNCTION_ARGUMENT; } - else if(data->conf & CONF_TELNET) { - result=telnet(data); - if(result) - return result; + if(conn->state != CONN_DO) { + /* This can only be called after a curl_do() */ + return CURLE_BAD_CALLING_ORDER; } - else if (data->conf & CONF_LDAP) { - result = ldap(data, path, &bytecount); - if (result) - return result; + data = conn->data; + + /* this calls the protocol-specific function pointer previously set */ + if(conn->curl_done) + result = conn->curl_done(conn); + else + result = CURLE_OK; + + pgrsDone(data); /* done with the operation */ + + conn->state = CONN_DONE; + + return result; +} + +CURLcode curl_do(CURLconnect *in_conn) +{ + struct connectdata *conn = in_conn; + CURLcode result; + + if(!conn || (conn->handle!= STRUCT_CONNECT)) { + return CURLE_BAD_FUNCTION_ARGUMENT; } - else if (data->conf & CONF_DICT) { - result = dict(data, path, &bytecount); - if(result) - return result; + if(conn->state != CONN_INIT) { + return CURLE_BAD_CALLING_ORDER; } - else { - result = http(data, ppath, name, &bytecount); - if(result) + + if(conn->curl_do) { + /* generic protocol-specific function pointer set in curl_connect() */ + result = conn->curl_do(conn); + if(result) { + conn->state = CONN_ERROR; return result; + } } - if(bytecount) { - double ittook = tvdiff (tvnow(), now); + + conn->state = CONN_DO; /* we have entered this state */ + +#if 0 + if(conn->bytecount) { + double ittook = tvdiff (tvnow(), conn->now); infof(data, "%i bytes transfered in %.3lf seconds (%.0lf bytes/sec).\n", - bytecount, ittook, (double)bytecount/(ittook!=0.0?ittook:1)); + conn->bytecount, ittook, (double)conn->bytecount/(ittook!=0.0?ittook:1)); } - return URG_OK; +#endif + return CURLE_OK; } -- cgit v1.2.3