From 4ad8e142da463ab208d5b5565e53291c8e5ef038 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 4 Aug 2013 19:34:16 +0200 Subject: [PATCH] urldata: clean up the use of the protocol specific structs 1 - always allocate the struct in protocol->setup_connection. Some protocol handlers had to get this function added. 2 - always free at the end of a request. This is also an attempt to keep less memory in the handle after it is completed. --- lib/easy.c | 5 +-- lib/file.c | 29 ++++---------- lib/ftp.c | 108 ++++++++++++++------------------------------------ lib/http.c | 35 ++++++++-------- lib/http.h | 3 +- lib/imap.c | 43 ++++++-------------- lib/pop3.c | 43 ++++++-------------- lib/rtsp.c | 35 ++++++++-------- lib/smtp.c | 44 +++++++------------- lib/ssh.c | 47 +++++----------------- lib/tftp.c | 12 ------ lib/url.c | 92 ++++++++++++++++++++++++------------------ lib/url.h | 5 --- lib/urldata.h | 7 ++-- 14 files changed, 185 insertions(+), 323 deletions(-) diff --git a/lib/easy.c b/lib/easy.c index 041a831b1..0ad03f961 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -602,9 +602,8 @@ void Curl_easy_addmulti(struct SessionHandle *data, void Curl_easy_initHandleData(struct SessionHandle *data) { - memset(&data->req, 0, sizeof(struct SingleRequest)); - - data->req.maxdownload = -1; + memset(&data->req, 0, sizeof(struct SingleRequest)); + data->req.maxdownload = -1; } /* diff --git a/lib/file.c b/lib/file.c index 038bf42e1..b77757596 100644 --- a/lib/file.c +++ b/lib/file.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -186,31 +186,16 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) char *actual_path; #endif - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - real_path = curl_easy_unescape(data, data->state.path, 0, NULL); if(!real_path) return CURLE_OUT_OF_MEMORY; - if(!data->state.proto.file) { - file = calloc(1, sizeof(struct FILEPROTO)); - if(!file) { - free(real_path); - return CURLE_OUT_OF_MEMORY; - } - data->state.proto.file = file; - } - else { - /* file is not a protocol that can deal with "persistancy" */ - file = data->state.proto.file; - Curl_safefree(file->freepath); - file->path = NULL; - if(file->fd != -1) - close(file->fd); - file->fd = -1; + file = calloc(1, sizeof(struct FILEPROTO)); + if(!file) { + free(real_path); + return CURLE_OUT_OF_MEMORY; } + data->state.proto.file = file; #ifdef DOS_FILESYSTEM /* If the first character is a slash, and there's @@ -450,7 +435,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) return file_upload(conn); /* get the fd from the connection phase */ - fd = conn->data->state.proto.file->fd; + fd = data->state.proto.file->fd; /* VMS: This only works reliable for STREAMLF files */ if(-1 != fstat(fd, &statbuf)) { diff --git a/lib/ftp.c b/lib/ftp.c index c9b97ddb5..6a9690992 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -225,7 +225,7 @@ const struct Curl_handler Curl_handler_ftps = { static const struct Curl_handler Curl_handler_ftp_proxy = { "FTP", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -251,7 +251,7 @@ static const struct Curl_handler Curl_handler_ftp_proxy = { static const struct Curl_handler Curl_handler_ftps_proxy = { "FTPS", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -3158,56 +3158,6 @@ static CURLcode ftp_block_statemach(struct connectdata *conn) return result; } -/* - * Allocate and initialize the struct FTP for the current SessionHandle. If - * need be. - */ - -#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ - defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) - /* workaround icc 9.1 optimizer issue */ -#pragma optimize("", off) -#endif - -static CURLcode ftp_init(struct connectdata *conn) -{ - struct FTP *ftp; - - if(NULL == conn->data->state.proto.ftp) { - conn->data->state.proto.ftp = malloc(sizeof(struct FTP)); - if(NULL == conn->data->state.proto.ftp) - return CURLE_OUT_OF_MEMORY; - } - - ftp = conn->data->state.proto.ftp; - - /* get some initial data into the ftp struct */ - ftp->bytecountp = &conn->data->req.bytecount; - ftp->transfer = FTPTRANSFER_BODY; - ftp->downloadsize = 0; - - /* No need to duplicate user+password, the connectdata struct won't change - during a session, but we re-init them here since on subsequent inits - since the conn struct may have changed or been replaced. - */ - ftp->user = conn->user; - ftp->passwd = conn->passwd; - if(isBadFtpString(ftp->user)) - return CURLE_URL_MALFORMAT; - if(isBadFtpString(ftp->passwd)) - return CURLE_URL_MALFORMAT; - - conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ - - return CURLE_OK; -} - -#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ - defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) - /* workaround icc 9.1 optimizer issue */ -#pragma optimize("", on) -#endif - /* * ftp_connect() should do everything that is to be considered a part of * the connection phase. @@ -3225,14 +3175,6 @@ static CURLcode ftp_connect(struct connectdata *conn, *done = FALSE; /* default to not done yet */ - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - result = ftp_init(conn); - if(CURLE_OK != result) - return result; - /* We always support persistent connections on ftp */ conn->bits.close = FALSE; @@ -4099,17 +4041,6 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done) *done = FALSE; /* default to false */ ftpc->wait_data_conn = FALSE; /* default to no such wait */ - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct FTP' to play with. For new connections, - the struct FTP is allocated and setup in the ftp_connect() function. - */ - Curl_reset_reqproto(conn); - retcode = ftp_init(conn); - if(retcode) - return retcode; - if(conn->data->set.wildcardmatch) { retcode = wc_statemach(conn); if(conn->data->wildcard.state == CURLWC_SKIP || @@ -4572,11 +4503,12 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, return result; } -static CURLcode ftp_setup_connection(struct connectdata * conn) +static CURLcode ftp_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; - char * type; + char *type; char command; + struct FTP *ftp; if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { /* Unless we have asked to tunnel ftp operations through the proxy, we @@ -4592,18 +4524,18 @@ static CURLcode ftp_setup_connection(struct connectdata * conn) return CURLE_UNSUPPORTED_PROTOCOL; #endif } - /* - * We explicitly mark this connection as persistent here as we're doing - * FTP over HTTP and thus we accidentally avoid setting this value - * otherwise. - */ - conn->bits.close = FALSE; + /* set it up as a HTTP connection instead */ + return conn->handler->setup_connection(conn); #else failf(data, "FTP over http proxy requires HTTP support built-in!"); return CURLE_UNSUPPORTED_PROTOCOL; #endif } + conn->data->state.proto.ftp = ftp = malloc(sizeof(struct FTP)); + if(NULL == ftp) + return CURLE_OUT_OF_MEMORY; + data->state.path++; /* don't include the initial slash */ data->state.slash_removed = TRUE; /* we've skipped the slash */ @@ -4636,6 +4568,24 @@ static CURLcode ftp_setup_connection(struct connectdata * conn) } } + /* get some initial data into the ftp struct */ + ftp->bytecountp = &conn->data->req.bytecount; + ftp->transfer = FTPTRANSFER_BODY; + ftp->downloadsize = 0; + + /* No need to duplicate user+password, the connectdata struct won't change + during a session, but we re-init them here since on subsequent inits + since the conn struct may have changed or been replaced. + */ + ftp->user = conn->user; + ftp->passwd = conn->passwd; + if(isBadFtpString(ftp->user)) + return CURLE_URL_MALFORMAT; + if(isBadFtpString(ftp->passwd)) + return CURLE_URL_MALFORMAT; + + conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ + return CURLE_OK; } diff --git a/lib/http.c b/lib/http.c index f4b7a48e7..8913c5a6d 100644 --- a/lib/http.c +++ b/lib/http.c @@ -105,7 +105,7 @@ static int https_getsock(struct connectdata *conn, */ const struct Curl_handler Curl_handler_http = { "HTTP", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -129,7 +129,7 @@ const struct Curl_handler Curl_handler_http = { */ const struct Curl_handler Curl_handler_https = { "HTTPS", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -149,6 +149,21 @@ const struct Curl_handler Curl_handler_https = { #endif +CURLcode Curl_http_setup_conn(struct connectdata *conn) +{ + /* allocate the HTTP-specific struct for the SessionHandle, only to survive + during this request */ + struct HTTP *http; + + DEBUGASSERT(conn->data->state.proto.http == NULL); + + conn->data->state.proto.http = http = calloc(1, sizeof(struct HTTP)); + if(!http) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + /* * checkheaders() checks the linked list of custom HTTP headers for a * particular header (prefix). @@ -1442,6 +1457,7 @@ CURLcode Curl_http_done(struct connectdata *conn, if(!premature && /* this check is pointless when DONE is called before the entire operation is complete */ !conn->bits.retry && + !data->set.connect_only && ((http->readbytecount + data->req.headerbytecount - data->req.deductheadercount)) <= 0) { @@ -1655,20 +1671,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) the rest of the request in the PERFORM phase. */ *done = TRUE; - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - if(!data->state.proto.http) { - /* Only allocate this struct if we don't already have it! */ - - http = calloc(1, sizeof(struct HTTP)); - if(!http) - return CURLE_OUT_OF_MEMORY; - data->state.proto.http = http; - } - else - http = data->state.proto.http; + http = data->state.proto.http; if(!data->state.this_is_a_follow) { /* this is not a followed location, get the original host name */ diff --git a/lib/http.h b/lib/http.h index 7236dd88c..ad2def81b 100644 --- a/lib/http.h +++ b/lib/http.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -66,6 +66,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, CURLcode Curl_http(struct connectdata *conn, bool *done); CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature); CURLcode Curl_http_connect(struct connectdata *conn, bool *done); +CURLcode Curl_http_setup_conn(struct connectdata *conn); /* The following functions are defined in http_chunks.c */ void Curl_httpchunk_init(struct connectdata *conn); diff --git a/lib/imap.c b/lib/imap.c index 13e9784a4..c1dffb41d 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -163,7 +163,7 @@ const struct Curl_handler Curl_handler_imaps = { static const struct Curl_handler Curl_handler_imap_proxy = { "IMAP", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -188,7 +188,7 @@ static const struct Curl_handler Curl_handler_imap_proxy = { static const struct Curl_handler Curl_handler_imaps_proxy = { "IMAPS", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -1669,13 +1669,11 @@ static CURLcode imap_init(struct connectdata *conn) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct IMAP *imap = data->state.proto.imap; + struct IMAP *imap; - if(!imap) { - imap = data->state.proto.imap = calloc(sizeof(struct IMAP), 1); - if(!imap) - result = CURLE_OUT_OF_MEMORY; - } + imap = data->state.proto.imap = calloc(sizeof(struct IMAP), 1); + if(!imap) + result = CURLE_OUT_OF_MEMORY; return result; } @@ -1705,15 +1703,6 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done) *done = FALSE; /* default to not done yet */ - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - /* Initialise the IMAP layer */ - result = imap_init(conn); - if(result) - return result; - /* We always support persistent connections in IMAP */ conn->bits.close = FALSE; @@ -1891,15 +1880,6 @@ static CURLcode imap_do(struct connectdata *conn, bool *done) *done = FALSE; /* default to false */ - /* Since connections can be re-used between SessionHandles, there might be a - connection already existing but on a fresh SessionHandle struct. As such - we make sure we have a good IMAP struct to play with. For new connections - the IMAP struct is allocated and setup in the imap_connect() function. */ - Curl_reset_reqproto(conn); - result = imap_init(conn); - if(result) - return result; - /* Parse the URL path */ result = imap_parse_url_path(conn); if(result) @@ -2018,6 +1998,11 @@ static CURLcode imap_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; + /* Initialise the IMAP layer */ + CURLcode result = imap_init(conn); + if(result) + return result; + if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { /* Unless we have asked to tunnel IMAP operations through the proxy, we switch and use HTTP operations only */ @@ -2033,10 +2018,8 @@ static CURLcode imap_setup_connection(struct connectdata *conn) #endif } - /* We explicitly mark this connection as persistent here as we're doing - IMAP over HTTP and thus we accidentally avoid setting this value - otherwise */ - conn->bits.close = FALSE; + /* set it up as an HTTP connection instead */ + return conn->handler->setup_connection(conn); #else failf(data, "IMAP over http proxy requires HTTP support built-in!"); return CURLE_UNSUPPORTED_PROTOCOL; diff --git a/lib/pop3.c b/lib/pop3.c index 876987f11..813414ebc 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -163,7 +163,7 @@ const struct Curl_handler Curl_handler_pop3s = { static const struct Curl_handler Curl_handler_pop3_proxy = { "POP3", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -188,7 +188,7 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { static const struct Curl_handler Curl_handler_pop3s_proxy = { "POP3S", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -1395,13 +1395,11 @@ static CURLcode pop3_init(struct connectdata *conn) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct POP3 *pop3 = data->state.proto.pop3; + struct POP3 *pop3; - if(!pop3) { - pop3 = data->state.proto.pop3 = calloc(sizeof(struct POP3), 1); - if(!pop3) - result = CURLE_OUT_OF_MEMORY; - } + pop3 = data->state.proto.pop3 = calloc(sizeof(struct POP3), 1); + if(!pop3) + result = CURLE_OUT_OF_MEMORY; return result; } @@ -1431,15 +1429,6 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done) *done = FALSE; /* default to not done yet */ - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - /* Initialise the POP3 layer */ - result = pop3_init(conn); - if(result) - return result; - /* We always support persistent connections in POP3 */ conn->bits.close = FALSE; @@ -1563,15 +1552,6 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done) *done = FALSE; /* default to false */ - /* Since connections can be re-used between SessionHandles, there might be a - connection already existing but on a fresh SessionHandle struct. As such - we make sure we have a good POP3 struct to play with. For new connections - the POP3 struct is allocated and setup in the pop3_connect() function. */ - Curl_reset_reqproto(conn); - result = pop3_init(conn); - if(result) - return result; - /* Parse the URL path */ result = pop3_parse_url_path(conn); if(result) @@ -1685,6 +1665,11 @@ static CURLcode pop3_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; + /* Initialise the POP3 layer */ + CURLcode result = pop3_init(conn); + if(result) + return result; + if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { /* Unless we have asked to tunnel POP3 operations through the proxy, we switch and use HTTP operations only */ @@ -1700,10 +1685,8 @@ static CURLcode pop3_setup_connection(struct connectdata *conn) #endif } - /* We explicitly mark this connection as persistent here as we're doing - POP3 over HTTP and thus we accidentally avoid setting this value - otherwise */ - conn->bits.close = FALSE; + /* set it up as an HTTP connection instead */ + return conn->handler->setup_connection(conn); #else failf(data, "POP3 over http proxy requires HTTP support built-in!"); return CURLE_UNSUPPORTED_PROTOCOL; diff --git a/lib/rtsp.c b/lib/rtsp.c index 3dc14901b..eac12904d 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -81,6 +81,8 @@ static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, ssize_t *nread, bool *readmore); +static CURLcode rtsp_setup_connection(struct connectdata *conn); + /* this returns the socket to wait for in the DO and DOING state for the multi interface and then we're always _sending_ a request and thus we wait for @@ -104,7 +106,7 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len); */ const struct Curl_handler Curl_handler_rtsp = { "RTSP", /* scheme */ - ZERO_NULL, /* setup_connection */ + rtsp_setup_connection, /* setup_connection */ rtsp_do, /* do_it */ rtsp_done, /* done */ ZERO_NULL, /* do_more */ @@ -122,6 +124,19 @@ const struct Curl_handler Curl_handler_rtsp = { PROTOPT_NONE /* flags */ }; + +static CURLcode rtsp_setup_connection(struct connectdata *conn) +{ + struct RTSP *rtsp; + + conn->data->state.proto.rtsp = rtsp = calloc(1, sizeof(struct RTSP)); + if(!rtsp) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; +} + + /* * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not * want to block the application forever while receiving a stream. Therefore, @@ -221,7 +236,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) struct SessionHandle *data = conn->data; CURLcode result=CURLE_OK; Curl_RtspReq rtspreq = data->set.rtspreq; - struct RTSP *rtsp; + struct RTSP *rtsp = data->state.proto.rtsp; struct HTTP *http; Curl_send_buffer *req_buffer; curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */ @@ -239,20 +254,6 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) *done = TRUE; - Curl_reset_reqproto(conn); - - if(!data->state.proto.rtsp) { - /* Only allocate this struct if we don't already have it! */ - - rtsp = calloc(1, sizeof(struct RTSP)); - if(!rtsp) - return CURLE_OUT_OF_MEMORY; - data->state.proto.rtsp = rtsp; - } - else { - rtsp = data->state.proto.rtsp; - } - http = &(rtsp->http_wrapper); /* Assert that no one has changed the RTSP struct in an evil way */ DEBUGASSERT((void *)http == (void *)rtsp); diff --git a/lib/smtp.c b/lib/smtp.c index 83fb9ec44..c1816e824 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -161,7 +161,7 @@ const struct Curl_handler Curl_handler_smtps = { static const struct Curl_handler Curl_handler_smtp_proxy = { "SMTP", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -186,7 +186,7 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { static const struct Curl_handler Curl_handler_smtps_proxy = { "SMTPS", /* scheme */ - ZERO_NULL, /* setup_connection */ + Curl_http_setup_conn, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ ZERO_NULL, /* do_more */ @@ -1361,13 +1361,11 @@ static CURLcode smtp_init(struct connectdata *conn) { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - struct SMTP *smtp = data->state.proto.smtp; + struct SMTP *smtp; - if(!smtp) { - smtp = data->state.proto.smtp = calloc(sizeof(struct SMTP), 1); - if(!smtp) - result = CURLE_OUT_OF_MEMORY; - } + smtp = data->state.proto.smtp = calloc(sizeof(struct SMTP), 1); + if(!smtp) + result = CURLE_OUT_OF_MEMORY; return result; } @@ -1397,15 +1395,6 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done) *done = FALSE; /* default to not done yet */ - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - /* Initialise the SMTP layer */ - result = smtp_init(conn); - if(result) - return result; - /* We always support persistent connections in SMTP */ conn->bits.close = FALSE; @@ -1571,15 +1560,6 @@ static CURLcode smtp_do(struct connectdata *conn, bool *done) *done = FALSE; /* default to false */ - /* Since connections can be re-used between SessionHandles, there might be a - connection already existing but on a fresh SessionHandle struct. As such - we make sure we have a good SMTP struct to play with. For new connections - the SMTP struct is allocated and setup in the smtp_connect() function. */ - Curl_reset_reqproto(conn); - result = smtp_init(conn); - if(result) - return result; - result = smtp_regular_transfer(conn, done); return result; @@ -1687,6 +1667,7 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn, static CURLcode smtp_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; + CURLcode result; if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { /* Unless we have asked to tunnel SMTP operations through the proxy, we @@ -1702,17 +1683,20 @@ static CURLcode smtp_setup_connection(struct connectdata *conn) return CURLE_UNSUPPORTED_PROTOCOL; #endif } + /* set it up as a HTTP connection instead */ + return conn->handler->setup_connection(conn); - /* We explicitly mark this connection as persistent here as we're doing - SMTP over HTTP and thus we accidentally avoid setting this value - otherwise */ - conn->bits.close = FALSE; #else failf(data, "SMTP over http proxy requires HTTP support built-in!"); return CURLE_UNSUPPORTED_PROTOCOL; #endif } + /* Initialise the SMTP layer */ + result = smtp_init(conn); + if(result) + return result; + data->state.path++; /* don't include the initial slash */ return CURLE_OK; diff --git a/lib/ssh.c b/lib/ssh.c index 422357be9..6f0923b52 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -149,13 +149,15 @@ static int ssh_perform_getsock(const struct connectdata *conn, number of sockets */ int numsocks); +static CURLcode ssh_setup_connection(struct connectdata *conn); + /* * SCP protocol handler. */ const struct Curl_handler Curl_handler_scp = { "SCP", /* scheme */ - ZERO_NULL, /* setup_connection */ + ssh_setup_connection, /* setup_connection */ ssh_do, /* do_it */ scp_done, /* done */ ZERO_NULL, /* do_more */ @@ -181,7 +183,7 @@ const struct Curl_handler Curl_handler_scp = { const struct Curl_handler Curl_handler_sftp = { "SFTP", /* scheme */ - ZERO_NULL, /* setup_connection */ + ssh_setup_connection, /* setup_connection */ ssh_do, /* do_it */ sftp_done, /* done */ ZERO_NULL, /* do_more */ @@ -200,7 +202,6 @@ const struct Curl_handler Curl_handler_sftp = { | PROTOPT_NOURLQUERY /* flags */ }; - static void kbd_callback(const char *name, int name_len, const char *instruction, int instruction_len, int num_prompts, @@ -2689,25 +2690,14 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, /* * SSH setup and connection */ -static CURLcode ssh_init(struct connectdata *conn) +static CURLcode ssh_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; struct SSHPROTO *ssh; - struct ssh_conn *sshc = &conn->proto.sshc; - sshc->actualcode = CURLE_OK; /* reset error code */ - sshc->secondCreateDirs =0; /* reset the create dir attempt state - variable */ - - if(data->state.proto.ssh) - return CURLE_OK; - - ssh = calloc(1, sizeof(struct SSHPROTO)); + conn->data->state.proto.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); if(!ssh) return CURLE_OUT_OF_MEMORY; - data->state.proto.ssh = ssh; - return CURLE_OK; } @@ -2731,14 +2721,6 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done) function to make the re-use checks properly be able to check this bit. */ conn->bits.close = FALSE; - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - - result = ssh_init(conn); - if(result) - return result; - if(conn->handler->protocol & CURLPROTO_SCP) { conn->recv[FIRSTSOCKET] = scp_recv; conn->send[FIRSTSOCKET] = scp_send; @@ -2856,23 +2838,16 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done) CURLcode res; bool connected = 0; struct SessionHandle *data = conn->data; + struct ssh_conn *sshc = &conn->proto.sshc; *done = FALSE; /* default to false */ - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct SSHPROTO' to play with. For new - connections, the struct SSHPROTO is allocated and setup in the - ssh_connect() function. - */ - Curl_reset_reqproto(conn); - res = ssh_init(conn); - if(res) - return res; - data->req.size = -1; /* make sure this is unknown at this point */ + sshc->actualcode = CURLE_OK; /* reset error code */ + sshc->secondCreateDirs =0; /* reset the create dir attempt state + variable */ + Curl_pgrsSetUploadCounter(data, 0); Curl_pgrsSetDownloadCounter(data, 0); Curl_pgrsSetUploadSize(data, 0); diff --git a/lib/tftp.c b/lib/tftp.c index ef740b856..b582ab319 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -947,10 +947,6 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) blksize = TFTP_BLKSIZE_DEFAULT; - /* If there already is a protocol-specific struct allocated for this - sessionhandle, deal with it */ - Curl_reset_reqproto(conn); - state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t)); if(!state) return CURLE_OUT_OF_MEMORY; @@ -1307,14 +1303,6 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done) *done = FALSE; - /* - Since connections can be re-used between SessionHandles, this might be a - connection already existing but on a fresh SessionHandle struct so we must - make sure we have a good 'struct TFTP' to play with. For new connections, - the struct TFTP is allocated and setup in the tftp_connect() function. - */ - Curl_reset_reqproto(conn); - if(!conn->proto.tftpc) { code = tftp_connect(conn, done); if(code) diff --git a/lib/url.c b/lib/url.c index 7cec5bccd..246b14293 100644 --- a/lib/url.c +++ b/lib/url.c @@ -148,6 +148,7 @@ static CURLcode parse_url_login(struct SessionHandle *data, static CURLcode parse_login_details(const char *login, const size_t len, char **userptr, char **passwdptr, char **optionsptr); +static void free_connection_internals(struct SessionHandle *data); /* * Protocol table. */ @@ -417,7 +418,8 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_safefree(data->state.pathbuffer); data->state.path = NULL; - Curl_safefree(data->state.proto.generic); + /* freed here just in case DONE wasn't called */ + free_connection_internals(data); /* Close down all open SSL info and sessions */ Curl_ssl_close_all(data); @@ -4016,18 +4018,28 @@ static CURLcode setup_range(struct SessionHandle *data) } -/*************************************************************** -* Setup connection internals specific to the requested protocol. -* This MUST get called after proxy magic has been figured out. -***************************************************************/ +/* + * setup_connection_internals() - + * + * Setup connection internals specific to the requested protocol in the + * SessionHandle. This is inited and setup before the connection is made but + * is about the particular protocol that is to be used. + * + * This MUST get called after proxy magic has been figured out. + */ static CURLcode setup_connection_internals(struct connectdata *conn) { const struct Curl_handler * p; CURLcode result; - conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ + /* in some case in the multi state-machine, we go back to the CONNECT state + and then a second (or third or...) call to this function will be made + without doing a DISCONNECT or DONE in between (since the connection is + yet in place) and therefore this function needs to first make sure + there's no lingering previous data allocated. */ + free_connection_internals(conn->data); - /* Scan protocol handler table. */ + conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ /* Perform setup complement if some. */ p = conn->handler; @@ -4045,11 +4057,21 @@ static CURLcode setup_connection_internals(struct connectdata *conn) /* we check for -1 here since if proxy was detected already, this was very likely already set to the proxy port */ conn->port = p->defport; - conn->remote_port = (unsigned short)conn->given->defport; + + /* only if remote_port was not already parsed off the URL we use the + default port number */ + if(!conn->remote_port) + conn->remote_port = (unsigned short)conn->given->defport; return CURLE_OK; } +static void free_connection_internals(struct SessionHandle *data) +{ + Curl_safefree(data->state.proto.generic); +} + + #ifndef CURL_DISABLE_PROXY /**************************************************************** * Checks if the host is in the noproxy list. returns true if it matches @@ -5217,6 +5239,27 @@ static CURLcode create_conn(struct SessionHandle *data, #endif /* CURL_DISABLE_PROXY */ + /************************************************************* + * If the protocol is using SSL and HTTP proxy is used, we set + * the tunnel_proxy bit. + *************************************************************/ + if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; + + /************************************************************* + * Figure out the remote port number and fix it in the URL + *************************************************************/ + result = parse_remote_port(data, conn); + if(result != CURLE_OK) + return result; + + /* Check for overridden login details and set them accordingly so they + they are known when protocol->setup_connection is called! */ + override_login(data, conn, user, passwd, options); + result = set_login(conn, user, passwd, options); + if(result != CURLE_OK) + return result; + /************************************************************* * Setup internals depending on protocol. Needs to be done after * we figured out what/if proxy to use. @@ -5266,32 +5309,12 @@ static CURLcode create_conn(struct SessionHandle *data, } /* since we skip do_init() */ - Curl_speedinit(data); + do_init(conn); return result; } #endif - /************************************************************* - * If the protocol is using SSL and HTTP proxy is used, we set - * the tunnel_proxy bit. - *************************************************************/ - if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy) - conn->bits.tunnel_proxy = TRUE; - - /************************************************************* - * Figure out the remote port number and fix it in the URL - *************************************************************/ - result = parse_remote_port(data, conn); - if(result != CURLE_OK) - return result; - - /* Check for overridden login details and set them accordingly */ - override_login(data, conn, user, passwd, options); - result = set_login(conn, user, passwd, options); - if(result != CURLE_OK) - return result; - /* Get a cloned copy of the SSL config situation stored in the connection struct. But to get this going nicely, we must first make sure that the strings in the master copy are pointing to the correct @@ -5728,6 +5751,7 @@ CURLcode Curl_done(struct connectdata **connp, this was either closed or handed over to the connection cache here, and therefore cannot be used from this point on */ + free_connection_internals(data); return result; } @@ -5861,13 +5885,3 @@ CURLcode Curl_do_more(struct connectdata *conn, int *complete) return result; } -/* Called on connect, and if there's already a protocol-specific struct - allocated for a different connection, this frees it that it can be setup - properly later on. */ -void Curl_reset_reqproto(struct connectdata *conn) -{ - struct SessionHandle *data = conn->data; - - Curl_safefree(data->state.proto.generic); - data->state.proto.generic = NULL; -} diff --git a/lib/url.h b/lib/url.h index c0d9c38dc..3fc635bdb 100644 --- a/lib/url.h +++ b/lib/url.h @@ -65,11 +65,6 @@ void Curl_getoff_all_pipelines(struct SessionHandle *data, void Curl_close_connections(struct SessionHandle *data); -/* Called on connect, and if there's already a protocol-specific struct - allocated for a different connection, this frees it that it can be setup - properly later on. */ -void Curl_reset_reqproto(struct connectdata *conn); - #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ #define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi service */ diff --git a/lib/urldata.h b/lib/urldata.h index d597c6744..7c150a55c 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1277,9 +1277,10 @@ struct UrlState { /* Protocol specific data. * ************************************************************************* - * Note that this data will be REMOVED after each request, so anything that - * should be kept/stored on a per-connection basis and thus live for the - * next request on the same connection MUST be put in the connectdata struct! + * Note that this data will be freed after each request is DONE, so anything + * that should be kept/stored on a per-connection basis and thus live for + * the next request on the same connection MUST be put in the connectdata + * struct! *************************************************************************/ union { struct HTTP *http;