Newer
Older
sval = Curl_socket_ready(sock, CURL_SOCKET_BAD, 0);
Daniel Stenberg
committed
if(sval == 0)
ret_val = FALSE;
static bool IsPipeliningPossible(const struct SessionHandle *handle)
{
if (handle->multi && Curl_multi_canPipeline(handle->multi) &&
(handle->set.httpreq == HTTPREQ_GET ||
handle->set.httpreq == HTTPREQ_HEAD) &&
handle->set.httpversion != CURL_HTTP_VERSION_1_0)
return TRUE;
return FALSE;
}
static bool IsPipeliningEnabled(const struct SessionHandle *handle)
Daniel Stenberg
committed
{
if (handle->multi && Curl_multi_canPipeline(handle->multi))
return TRUE;
return FALSE;
}
CURLcode Curl_addHandleToPipeline(struct SessionHandle *data,
struct curl_llist *pipe)
{
Daniel Stenberg
committed
#ifdef CURLDEBUG
if(!IsPipeliningPossible(data)) {
/* when not pipelined, there MUST be no handle in the list already */
if(pipe->head)
infof(data, "PIPE when no PIPE supposed!\n");
}
#endif
if (!Curl_llist_insert_next(pipe, pipe->tail, data))
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
}
Daniel Stenberg
committed
int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
struct curl_llist *pipe)
{
struct curl_llist_element *curr;
curr = pipe->head;
while (curr) {
if (curr->ptr == handle) {
Curl_llist_remove(pipe, curr, NULL);
Daniel Stenberg
committed
return 1; /* we removed a handle */
}
curr = curr->next;
}
Daniel Stenberg
committed
Daniel Stenberg
committed
return 0;
}
Daniel Stenberg
committed
#if 0 /* this code is saved here as it is useful for debugging purposes */
static void Curl_printPipeline(struct curl_llist *pipe)
{
struct curl_llist_element *curr;
curr = pipe->head;
while (curr) {
struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
infof(data, "Handle in pipeline: %s\n", data->reqdata.path);
curr = curr->next;
}
}
#endif
bool Curl_isHandleAtHead(struct SessionHandle *handle,
struct curl_llist *pipe)
{
struct curl_llist_element *curr = pipe->head;
if (curr) {
}
return FALSE;
}
static struct SessionHandle* gethandleathead(struct curl_llist *pipe)
{
struct curl_llist_element *curr = pipe->head;
if (curr) {
return (struct SessionHandle *) curr->ptr;
}
return NULL;
}
static void signalPipeClose(struct curl_llist *pipe)
{
struct curl_llist_element *curr;
if (!pipe)
return;
curr = pipe->head;
while (curr) {
struct curl_llist_element *next = curr->next;
struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
Daniel Stenberg
committed
#ifdef CURLDEBUG /* debug-only code */
if(data->magic != CURLEASY_MAGIC_NUMBER) {
/* MAJOR BADNESS */
infof(data, "signalPipeClose() found BAAD easy handle\n");
Daniel Stenberg
committed
}
#endif
Daniel Stenberg
committed
data->state.pipe_broke = TRUE;
Curl_multi_handlePipeBreak(data);
Curl_llist_remove(pipe, curr, NULL);
curr = next;
}
}
* Given one filled in connection struct (named needle), this function should
* detect if there already is one that has all the significant details
* exactly the same and thus should be used instead.
*
* If there is a match, this function returns TRUE - and has marked the
* connection as 'in-use'. It must later be called with ConnectionDone() to
* return back to 'idle' (unused) state.
Daniel Stenberg
committed
ConnectionExists(struct SessionHandle *data,
struct connectdata *needle,
struct connectdata **usethis)
struct connectdata *check;
bool canPipeline = IsPipeliningPossible(data);
for(i=0; i< data->state.connc->num; i++) {
bool match = FALSE;
/*
* Note that if we use a HTTP proxy, we check connections to that
* proxy and not to the actual remote server.
*/
check = data->state.connc->connects[i];
if(!check)
/* NULL pointer means not filled-in entry */
continue;
pipeLen = check->send_pipe->size + check->recv_pipe->size;
Daniel Stenberg
committed
if (check->connectindex == -1) {
check->connectindex = i; /* Set this appropriately since it might have
been set to -1 when the easy was removed
from the multi */
}
if(pipeLen > 0 && !canPipeline) {
Daniel Stenberg
committed
/* can only happen within multi handles, and means that another easy
handle is using this connection */
Daniel Stenberg
committed
continue;
}
Daniel Stenberg
committed
#ifdef CURLRES_ASYNCH
Daniel Stenberg
committed
/* ip_addr_str is NULL only if the resolving of the name hasn't completed
yet and until then we don't re-use this connection */
Daniel Stenberg
committed
if (!check->ip_addr_str) {
infof(data,
"Connection #%ld hasn't finished name resolve, can't reuse\n",
Daniel Stenberg
committed
check->connectindex);
continue;
Daniel Stenberg
committed
}
#endif
if ((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || check->bits.close) {
/* Don't pick a connection that hasn't connected yet or that is going to
get closed. */
infof(data, "Connection #%ld isn't open enough, can't reuse\n",
check->connectindex);
#ifdef CURLDEBUG
if (check->recv_pipe->size > 0) {
infof(data, "BAD! Unconnected #%ld has a non-empty recv pipeline!\n",
check->connectindex);
}
#endif
continue;
}
if (pipeLen >= MAX_PIPELINE_LENGTH) {
Daniel Stenberg
committed
infof(data, "Connection #%ld has its pipeline full, can't reuse\n",
check->connectindex);
continue;
Daniel Stenberg
committed
}
if (canPipeline) {
/* Make sure the pipe has only GET requests */
struct SessionHandle* sh = gethandleathead(check->send_pipe);
struct SessionHandle* rh = gethandleathead(check->recv_pipe);
if (sh) {
if(!IsPipeliningPossible(sh))
continue;
}
else if (rh) {
if(!IsPipeliningPossible(rh))
continue;
}
}
if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL))
/* don't do mixed SSL and non-SSL connections */
continue;
if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) {
/* The requested connection does not use a HTTP proxy or it
uses SSL. */
if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy)
/* we don't do SSL but the cached connection has a proxy,
then don't match this */
continue;
if(strequal(needle->protostr, check->protostr) &&
strequal(needle->host.name, check->host.name) &&
(needle->remote_port == check->remote_port) ) {
Daniel Stenberg
committed
if(needle->protocol & PROT_SSL) {
/* This is SSL, verify that we're using the same
ssl options as well */
if(!Curl_ssl_config_matches(&needle->ssl_config,
&check->ssl_config)) {
Daniel Stenberg
committed
infof(data,
"Connection #%ld has different SSL parameters, "
"can't reuse\n",
check->connectindex );
Daniel Stenberg
committed
continue;
}
}
if((needle->protocol & PROT_FTP) ||
((needle->protocol & PROT_HTTP) &&
(data->state.authhost.want==CURLAUTH_NTLM))) {
/* This is FTP or HTTP+NTLM, verify that we're using the same name
and password as well */
if(!strequal(needle->user, check->user) ||
!strequal(needle->passwd, check->passwd)) {
/* one of them was different */
continue;
}
}
match = TRUE;
else { /* The requested needle connection is using a proxy,
Daniel Stenberg
committed
is the checked one using the same host, port and type? */
if(check->bits.proxy &&
(needle->proxytype == check->proxytype) &&
strequal(needle->proxy.name, check->proxy.name) &&
needle->port == check->port) {
/* This is the same proxy connection, use it! */
match = TRUE;
}
}
if(match) {
Daniel Stenberg
committed
if (!IsPipeliningEnabled(data)) {
/* The check for a dead socket makes sense only in the
non-pipelining case */
bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
if(dead) {
Daniel Stenberg
committed
check->data = data;
Daniel Stenberg
committed
infof(data, "Connection #%d seems to be dead!\n", i);
Daniel Stenberg
committed
Curl_disconnect(check); /* disconnect resources */
data->state.connc->connects[i]=NULL; /* nothing here */
Daniel Stenberg
committed
return FALSE;
}
check->inuse = TRUE; /* mark this as being in use so that no other
handle in a multi stack may nick it */
if (canPipeline) {
Daniel Stenberg
committed
/* Mark the connection as being in a pipeline */
check->is_in_pipeline = TRUE;
}
*usethis = check;
return TRUE; /* yes, we found one to use! */
Daniel Stenberg
committed
return FALSE; /* no matching connecting exists */
}
Daniel Stenberg
committed
/*
* This function frees/closes a connection in the connection cache. This
* should take the previously set policy into account when deciding which
* of the connections to kill.
*/
Daniel Stenberg
committed
ConnectionKillOne(struct SessionHandle *data)
long highscore=-1;
long connindex=-1;
long score;
struct timeval now;
now = Curl_tvnow();
for(i=0; data->state.connc && (i< data->state.connc->num); i++) {
conn = data->state.connc->connects[i];
Daniel Stenberg
committed
if(!conn || conn->inuse)
/* Set higher score for the age passed since the connection was used */
score = Curl_tvdiff(now, conn->now);
if(score > highscore) {
highscore = score;
connindex = i;
}
}
if(connindex >= 0) {
/* Set the connection's owner correctly */
conn = data->state.connc->connects[connindex];
conn->data = data;
/* the winner gets the honour of being disconnected */
(void)Curl_disconnect(conn);
/* clean the array entry */
data->state.connc->connects[connindex] = NULL;
}
return connindex; /* return the available index or -1 */
}
/* this connection can now be marked 'idle' */
static void
ConnectionDone(struct connectdata *conn)
{
conn->inuse = FALSE;
if (!conn->send_pipe && !conn->recv_pipe)
Daniel Stenberg
committed
conn->is_in_pipeline = FALSE;
}
/*
* The given input connection struct pointer is to be stored. If the "cache"
* is already full, we must clean out the most suitable using the previously
* set policy.
*
* The given connection should be unique. That must've been checked prior to
* this call.
*/
Daniel Stenberg
committed
ConnectionStore(struct SessionHandle *data,
struct connectdata *conn)
{
for(i=0; i< data->state.connc->num; i++) {
if(!data->state.connc->connects[i])
if(i == data->state.connc->num) {
/* there was no room available, kill one */
i = ConnectionKillOne(data);
Daniel Stenberg
committed
if(-1 != i)
Daniel Stenberg
committed
infof(data, "Connection (#%d) was killed to make room (holds %d)\n",
i, data->state.connc->num);
Daniel Stenberg
committed
else
infof(data, "This connection did not fit in the connection cache\n");
conn->connectindex = i; /* Make the child know where the pointer to this
particular data is stored. But note that this -1
if this is not within the cache and this is
probably not checked for everywhere (yet). */
conn->inuse = TRUE;
if(-1 != i) {
/* Only do this if a true index was returned, if -1 was returned there
is no room in the cache for an unknown reason and we cannot store
this there.
TODO: make sure we really can work with more handles than positions in
the cache, or possibly we should (allow to automatically) resize the
connection cache when we add more easy handles to a multi handle!
*/
data->state.connc->connects[i] = conn; /* fill in this */
conn->data = data;
static CURLcode ConnectPlease(struct SessionHandle *data,
struct connectdata *conn,
struct Curl_dns_entry *hostaddr,
bool *connected)
Daniel Stenberg
committed
Curl_addrinfo *addr;
Daniel Stenberg
committed
char *hostname = conn->bits.proxy?conn->proxy.name:conn->host.name;
Daniel Stenberg
committed
Daniel Stenberg
committed
infof(data, "About to connect() to %s%s port %d (#%d)\n",
Daniel Stenberg
committed
conn->bits.proxy?"proxy ":"",
Daniel Stenberg
committed
hostname, conn->port, conn->connectindex);
/*************************************************************
*************************************************************/
hostaddr,
Daniel Stenberg
committed
&conn->sock[FIRSTSOCKET],
&addr,
connected);
Daniel Stenberg
committed
/* All is cool, then we store the current information */
conn->dns_entry = hostaddr;
conn->ip_addr = addr;
Daniel Stenberg
committed
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
result = Curl_store_ip_addr(conn);
if(CURLE_OK == result) {
switch(data->set.proxytype) {
case CURLPROXY_SOCKS5:
result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, conn->host.name,
conn->remote_port, FIRSTSOCKET, conn);
break;
case CURLPROXY_HTTP:
/* do nothing here. handled later. */
break;
case CURLPROXY_SOCKS4:
result = Curl_SOCKS4(conn->proxyuser, conn->host.name, conn->remote_port,
FIRSTSOCKET, conn);
break;
default:
failf(data, "unknown proxytype option given");
result = CURLE_COULDNT_CONNECT;
break;
}
Daniel Stenberg
committed
}
}
Daniel Stenberg
committed
if(result)
*connected = FALSE; /* mark it as not connected */
* verboseconnect() displays verbose information after a connect
static void verboseconnect(struct connectdata *conn)
Daniel Stenberg
committed
{
Daniel Stenberg
committed
infof(conn->data, "Connected to %s (%s) port %d (#%d)\n",
Daniel Stenberg
committed
conn->bits.proxy ? conn->proxy.dispname : conn->host.dispname,
Daniel Stenberg
committed
conn->ip_addr_str, conn->port, conn->connectindex);
Daniel Stenberg
committed
}
Daniel Stenberg
committed
Daniel Stenberg
committed
int Curl_protocol_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
{
Daniel Stenberg
committed
if(conn->curl_proto_getsock)
return conn->curl_proto_getsock(conn, socks, numsocks);
return GETSOCK_BLANK;
}
Daniel Stenberg
committed
int Curl_doing_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
{
Daniel Stenberg
committed
if(conn && conn->curl_doing_getsock)
return conn->curl_doing_getsock(conn, socks, numsocks);
return GETSOCK_BLANK;
}
/*
* We are doing protocol-specific connecting and this is being called over and
* over from the multi interface until the connection phase is done on
* protocol layer.
*/
CURLcode Curl_protocol_connecting(struct connectdata *conn,
bool *done)
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
{
CURLcode result=CURLE_OK;
if(conn && conn->curl_connecting) {
*done = FALSE;
result = conn->curl_connecting(conn, done);
}
else
*done = TRUE;
return result;
}
/*
* We are DOING this is being called over and over from the multi interface
* until the DOING phase is done on protocol layer.
*/
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
{
CURLcode result=CURLE_OK;
if(conn && conn->curl_doing) {
*done = FALSE;
result = conn->curl_doing(conn, done);
}
else
*done = TRUE;
return result;
}
/*
* We have discovered that the TCP connection has been successful, we can now
* proceed with some action.
*
*/
CURLcode Curl_protocol_connect(struct connectdata *conn,
bool *protocol_done)
{
CURLcode result=CURLE_OK;
struct SessionHandle *data = conn->data;
*protocol_done = FALSE;
if(conn->bits.tcpconnect && conn->bits.protoconnstart) {
/* 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. Note that we don't know if the protocol is actually done.
Unless this protocol doesn't have any protocol-connect callback, as
then we know we're done. */
if(!conn->curl_connecting)
*protocol_done = TRUE;
return CURLE_OK;
}
if(!conn->bits.tcpconnect) {
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
if(data->set.verbose)
verboseconnect(conn);
}
if(!conn->bits.protoconnstart) {
if(conn->curl_connect) {
/* is there a protocol-specific connect() procedure? */
/* Set start time here for timeout purposes in the connect procedure, it
is later set again for the progress meter purpose */
conn->now = Curl_tvnow();
/* Call the protocol-specific connect function */
result = conn->curl_connect(conn, protocol_done);
}
else
*protocol_done = TRUE;
/* it has started, possibly even completed but that knowledge isn't stored
in this bit! */
Daniel Stenberg
committed
if (!result)
conn->bits.protoconnstart = TRUE;
}
return result; /* pass back status */
}
/*
* Helpers for IDNA convertions.
*/
#ifdef USE_LIBIDN
static bool is_ASCII_name(const char *hostname)
{
const unsigned char *ch = (const unsigned char*)hostname;
while (*ch) {
if (*ch++ & 0x80)
return FALSE;
}
return TRUE;
}
/*
* Check if characters in hostname is allowed in Top Level Domain.
*/
static bool tld_check_name(struct SessionHandle *data,
const char *ace_hostname)
char *tld_errmsg = (char *)"<no msg>";
/* Convert (and downcase) ACE-name back into locale's character set */
rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0);
if (rc != IDNA_SUCCESS)
#ifdef HAVE_TLD_STRERROR
#endif
if (rc == TLD_INVALID)
infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
tld_errmsg, err_pos, uc_name[err_pos],
uc_name[err_pos] & 255);
infof(data, "WARNING: TLD check for %s failed; %s\n",
uc_name, tld_errmsg);
#endif /* CURL_DISABLE_VERBOSE_STRINGS */
#endif
static void fix_hostname(struct SessionHandle *data,
struct connectdata *conn, struct hostname *host)
{
#ifndef USE_LIBIDN
(void)data;
(void)conn;
#elif defined(CURL_DISABLE_VERBOSE_STRINGS)
(void)conn;
#endif
/* set the name we use to display the host name */
#ifdef USE_LIBIDN
/*************************************************************
* Check name for non-ASCII and convert hostname to ACE form.
*************************************************************/
Daniel Stenberg
committed
if (!is_ASCII_name(host->name) &&
stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
char *ace_hostname = NULL;
int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
infof (data, "Input domain encoded as `%s'\n",
stringprep_locale_charset ());
if (rc != IDNA_SUCCESS)
infof(data, "Failed to convert %s to ACE; %s\n",
host->name, Curl_idn_strerror(conn,rc));
else {
/* tld_check_name() displays a warning if the host name contains
"illegal" characters for this TLD */
(void)tld_check_name(data, ace_hostname);
host->encalloc = ace_hostname;
/* change the name pointer to point to the encoded hostname */
host->name = host->encalloc;
}
}
}
/*
* Parse URL and fill in the relevant members of the connection struct.
Daniel Stenberg
committed
*/
static CURLcode ParseURLAndFillConnection(struct SessionHandle *data,
struct connectdata *conn)
Daniel Stenberg
committed
char *at;
char *tmp;
char *path = data->reqdata.path;
/*************************************************************
* Parse the URL.
*
* We need to parse the url even when using the proxy, because we will need
* the hostname and port in case we are trying to SSL connect through the
* proxy -- and we don't know if we will need to use SSL until we parse the
* url ...
************************************************************/
if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]",
path)) && strequal(conn->protostr, "file")) {
if(path[0] == '/' && path[1] == '/') {
/* Allow omitted hostname (e.g. file:/<path>). This is not strictly
* speaking a valid file: URL by RFC 1738, but treating file:/<path> as
* file://localhost/<path> is similar to how other schemes treat missing
* hostnames. See RFC 1808. */
/* This cannot be done with strcpy() in a portable manner, since the
memory areas overlap! */
memmove(path, path + 2, strlen(path + 2)+1);
}
/*
* we deal with file://<host>/<path> differently since it supports no
* hostname other than "localhost" and "127.0.0.1", which is unique among
* the URL protocols specified in RFC 1738
*/
if(path[0] != '/') {
/* the URL included a host name, we ignore host names in file:// URLs
as the standards don't define what to do with them */
char *ptr=strchr(path, '/');
The rest of the locator consists of data specific to the scheme,
and is known as the "url-path". It supplies the details of how the
specified resource can be accessed. Note that the "/" between the
host (or port) and the url-path is NOT part of the url-path.
As most agents use file://localhost/foo to get '/foo' although the
slash preceding foo is a separator and not a slash for the path,
a URL as file://localhost//foo must be valid as well, to refer to
the same file with an absolute path.
*/
if(ptr[1] && ('/' == ptr[1]))
/* if there was two slashes, we skip the first one as that is then
used truly as a separator */
Daniel Stenberg
committed
/* This cannot be made with strcpy, as the memory chunks overlap! */
memmove(path, ptr, strlen(ptr)+1);
strcpy(conn->protostr, "file"); /* store protocol string lowercase */
/* clear path */
path[0]=0;
Daniel Stenberg
committed
if (2 > sscanf(data->change.url,
Daniel Stenberg
committed
"%15[^\n:]://%[^\n/]%[^\n]",
Daniel Stenberg
committed
conn->protostr,
conn->host.name, path)) {
/*
* The URL was badly formatted, let's try the browser-style _without_
* protocol specified like 'http://'.
*/
Daniel Stenberg
committed
if((1 > sscanf(data->change.url, "%[^\n/]%[^\n]",
conn->host.name, path)) ) {
/*
* We couldn't even get this format.
*/
failf(data, "<url> malformed");
return CURLE_URL_MALFORMAT;
}
/*
* Since there was no protocol part specified, we guess what protocol it
* is based on the first letters of the server name.
*/
/* Note: if you add a new protocol, please update the list in
* lib/version.c too! */
if(checkprefix("FTP.", conn->host.name))
strcpy(conn->protostr, "ftp");
Daniel Stenberg
committed
else if (checkprefix("DICT.", conn->host.name))
strcpy(conn->protostr, "DICT");
Daniel Stenberg
committed
else if (checkprefix("LDAP.", conn->host.name))
strcpy(conn->protostr, "LDAP");
strcpy(conn->protostr, "http");
}
conn->protocol |= PROT_MISSING; /* not given in URL */
}
Daniel Stenberg
committed
/* We search for '?' in the host name (but only on the right side of a
* @-letter to allow ?-letters in username and password) to handle things
* like http://example.com?param= (notice the missing '/').
*/
at = strchr(conn->host.name, '@');
if(at)
tmp = strchr(at+1, '?');
else
tmp = strchr(conn->host.name, '?');
if(tmp) {
/* We must insert a slash before the '?'-letter in the URL. If the URL had
a slash after the '?', that is where the path currently begins and the
'?string' is still part of the host name.
We must move the trailing part from the host name and put it first in
the path. And have it all prefixed with a slash.
*/
size_t hostlen = strlen(tmp);
size_t pathlen = strlen(path);
/* move the existing path plus the zero byte forward, to make room for
the host-name part */
memmove(path+hostlen+1, path, pathlen+1);
/* now copy the trailing host part in front of the existing path */
memcpy(path+1, tmp, hostlen);
path[0]='/'; /* prepend the missing slash */
Daniel Stenberg
committed
*tmp=0; /* now cut off the hostname at the ? */
}
else if(!path[0]) {
/* if there's no path set, use a single slash */
strcpy(path, "/");
Daniel Stenberg
committed
Daniel Stenberg
committed
/* If the URL is malformatted (missing a '/' after hostname before path) we
* insert a slash here. The only letter except '/' we accept to start a path
* is '?'.
*/
if(path[0] == '?') {
Daniel Stenberg
committed
/* We need this function to deal with overlapping memory areas. We know
that the memory area 'path' points to is 'urllen' bytes big and that
is bigger than the path. Use +1 to move the zero byte too. */
memmove(&path[1], path, strlen(path)+1);
path[0] = '/';
Daniel Stenberg
committed
}
/*
* So if the URL was A://B/C,
* conn->protostr is A
* conn->host.name is B
* data->reqdata.path is /C
*/
return CURLE_OK;
}
static void llist_dtor(void *user, void *element)
{
(void)user;
(void)element;
/* Do nothing */
}
Daniel Stenberg
committed
static CURLcode setup_range(struct SessionHandle *data)
{
/*
* If we're doing a resumed transfer, we need to setup our stuff
* properly.
*/
struct HandleData *req = &data->reqdata;
req->resume_from = data->set.set_resume_from;
Daniel Stenberg
committed
if (req->resume_from || data->set.str[STRING_SET_RANGE]) {
if (req->rangestringalloc)
Daniel Stenberg
committed
free(req->range);
if(req->resume_from)
req->range = aprintf("%" FORMAT_OFF_T "-", req->resume_from);
else
Daniel Stenberg
committed
req->range = strdup(data->set.str[STRING_SET_RANGE]);
Daniel Stenberg
committed
req->rangestringalloc = req->range?TRUE:FALSE;
if(!req->range)
return CURLE_OUT_OF_MEMORY;
/* tell ourselves to fetch this range */
req->use_range = TRUE; /* enable range download */
}
else
req->use_range = FALSE; /* disable range download */
return CURLE_OK;
}
/***************************************************************
* Setup connection internals specific to the requested protocol
***************************************************************/
static CURLcode setup_connection_internals(struct SessionHandle *data,
struct connectdata *conn)
{
Daniel Stenberg
committed
conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
if (strequal(conn->protostr, "HTTP")) {
#ifndef CURL_DISABLE_HTTP
Daniel Stenberg
committed
conn->port = PORT_HTTP;
conn->remote_port = PORT_HTTP;
conn->curl_do = Curl_http;
conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
conn->curl_done = Curl_http_done;
conn->curl_connect = Curl_http_connect;
#else
failf(data, LIBCURL_NAME
" was built with HTTP disabled, http: not supported!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
else if (strequal(conn->protostr, "HTTPS")) {
Daniel Stenberg
committed
#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
Daniel Stenberg
committed
conn->port = PORT_HTTPS;
conn->remote_port = PORT_HTTPS;
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
conn->curl_do = Curl_http;
conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
conn->curl_done = Curl_http_done;
conn->curl_connect = Curl_http_connect;
Daniel Stenberg
committed
conn->curl_connecting = Curl_https_connecting;
Daniel Stenberg
committed
conn->curl_proto_getsock = Curl_https_getsock;
failf(data, LIBCURL_NAME
" was built with SSL disabled, https: not supported!");
Daniel Stenberg
committed
#endif /* !USE_SSL */
else if(strequal(conn->protostr, "FTP") ||
strequal(conn->protostr, "FTPS")) {
#ifndef CURL_DISABLE_FTP
int port = PORT_FTP;
Daniel Stenberg
committed
#ifdef USE_SSL
conn->protocol |= PROT_FTPS|PROT_SSL;
/* send data securely unless specifically requested otherwise */
conn->ssl[SECONDARYSOCKET].use = data->set.ftp_ssl != CURLFTPSSL_CONTROL;
port = PORT_FTPS;
failf(data, LIBCURL_NAME
" was built with SSL disabled, ftps: not supported!");
Daniel Stenberg
committed
#endif /* !USE_SSL */
Daniel Stenberg
committed
conn->port = port;
conn->protocol |= PROT_FTP;
Daniel Stenberg
committed
if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
/* Unless we have asked to tunnel ftp operations through the proxy, we
switch and use HTTP operations only */
#ifndef CURL_DISABLE_HTTP
conn->curl_do = Curl_http;
conn->curl_done = Curl_http_done;
Daniel Stenberg
committed
conn->protocol = PROT_HTTP; /* switch to HTTP */
#else
failf(data, "FTP over http proxy requires HTTP support built-in!");
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
conn->curl_do = Curl_ftp;
conn->curl_do_more = Curl_ftp_nextconnect;
conn->curl_done = Curl_ftp_done;
conn->curl_connect = Curl_ftp_connect;
conn->curl_connecting = Curl_ftp_multi_statemach;
conn->curl_doing = Curl_ftp_doing;
Daniel Stenberg
committed
conn->curl_proto_getsock = Curl_ftp_getsock;
conn->curl_doing_getsock = Curl_ftp_getsock;
data->reqdata.path++; /* don't include the initial slash */
/* FTP URLs support an extension like ";type=<typecode>" that
type=strstr(data->reqdata.path, ";type=");
type=strstr(conn->host.rawalloc, ";type=");
*type=0; /* it was in the middle of the hostname */