Curl_httpchunk_init(data, &ts->ch, TRUE);
*pts = ts;
- connkeep(cf->conn, "HTTP proxy CONNECT");
return tunnel_reinit(cf, data, ts);
}
CURL_TRC_CF(data, cf, "CONNECT need to close+open");
infof(data, "Connect me again please");
Curl_conn_cf_close(cf, data);
- connkeep(conn, "HTTP proxy CONNECT");
result = Curl_conn_cf_connect(cf->next, data, &done);
goto out;
}
if(data->info.httpproxycode/100 != 2) {
/* a non-2xx response and we have no next URL to try. */
Curl_safefree(data->req.newurl);
- /* failure, close this connection to avoid reuse */
- streamclose(conn, "proxy CONNECT failure");
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
return CURLE_RECV_ERROR;
return result;
}
- if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
- connclose(cf->conn, "GOAWAY received");
- }
-
return CURLE_OK;
}
if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
"connection", ctx->tunnel.stream_id);
- connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
+ failf(data, "proxy server refused HTTP/2 stream");
return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
}
else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) {
while(conn) {
cpool_remove_conn(cpool, conn);
sigpipe_apply(cpool->idata, &pipe_st);
- connclose(conn, "kill all");
cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
conn = cpool_get_first(cpool);
}
CURLPROTO_FTP, /* family */
PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
- PROTOPT_WILDCARD | PROTOPT_SSL_REUSE /* flags */
+ PROTOPT_WILDCARD | PROTOPT_SSL_REUSE |
+ PROTOPT_CONN_REUSE /* flags */
};
CURLPROTO_FTPS, /* protocol */
CURLPROTO_FTP, /* family */
PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
- PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
+ PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD |
+ PROTOPT_CONN_REUSE /* flags */
};
#endif
if(!ftpc)
return CURLE_FAILED_INIT;
pp = &ftpc->pp;
- /* We always support persistent connections on ftp */
- connkeep(conn, "FTP default");
-
PINGPONG_SETUP(pp, ftp_pp_statemachine, ftp_endofresp);
if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
CURLPROTO_HTTP, /* protocol */
CURLPROTO_HTTP, /* family */
PROTOPT_CREDSPERREQUEST | /* flags */
- PROTOPT_USERPWDCTRL
+ PROTOPT_USERPWDCTRL | PROTOPT_CONN_REUSE
+
};
#ifdef USE_SSL
CURLPROTO_HTTPS, /* protocol */
CURLPROTO_HTTP, /* family */
PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN | /* flags */
- PROTOPT_USERPWDCTRL
+ PROTOPT_USERPWDCTRL | PROTOPT_CONN_REUSE
};
#endif
{
/* allocate the HTTP-specific struct for the Curl_easy, only to survive
during this request */
- connkeep(conn, "HTTP default");
if(data->state.http_neg.wanted == CURL_HTTP_V3x) {
/* only HTTP/3, needs to work */
CURLcode result = Curl_conn_may_http3(data, conn, conn->transport_wanted);
*/
CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
{
- struct connectdata *conn = data->conn;
-
- /* We default to persistent connections. We set this already in this connect
- function to make the reuse checks properly be able to check this bit. */
- connkeep(conn, "HTTP default");
-
return Curl_conn_connect(data, FIRSTSOCKET, FALSE, done);
}
}
return CURLE_OK;
}
- if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
+ if((k->httpversion < 20) &&
+ HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
/*
* [RFC 2616, section 8.1.2.1]
* "Connection: close" is HTTP/1.1 language and means that
* the connection will close when this request has been
* served.
*/
- streamclose(conn, "Connection: close used");
+ connclose(conn, "Connection: close used");
return CURLE_OK;
}
if((k->httpversion == 10) &&
size_t nread;
if(should_close_session(ctx)) {
- CURL_TRC_CF(data, cf, "progress ingress, session is closed");
+ CURL_TRC_CF(data, cf, "[0] ingress: session is closed");
return CURLE_HTTP2;
}
result = h2_process_pending_input(cf, data);
if(result)
return result;
- CURL_TRC_CF(data, cf, "[0] progress ingress: inbufg=%zu",
+ CURL_TRC_CF(data, cf, "[0] ingress: nw-in buffered %zu",
Curl_bufq_len(&ctx->inbufq));
}
if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
- connclose(cf->conn, "GOAWAY received");
+ connclose(cf->conn, ctx->rcvd_goaway ? "server closed with GOAWAY" :
+ "server closed abruptly");
}
- CURL_TRC_CF(data, cf, "[0] progress ingress: done");
+ CURL_TRC_CF(data, cf, "[0] ingress: done");
return CURLE_OK;
}
PORT_IMAP, /* defport */
CURLPROTO_IMAP, /* protocol */
CURLPROTO_IMAP, /* family */
- PROTOPT_CLOSEACTION| /* flags */
- PROTOPT_URLOPTIONS|
- PROTOPT_SSL_REUSE
+ PROTOPT_CLOSEACTION | /* flags */
+ PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE |
+ PROTOPT_CONN_REUSE
};
#ifdef USE_SSL
CURLPROTO_IMAPS, /* protocol */
CURLPROTO_IMAP, /* family */
PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
- PROTOPT_URLOPTIONS
+ PROTOPT_URLOPTIONS | PROTOPT_CONN_REUSE
};
#endif
if(!imapc)
return CURLE_FAILED_INIT;
- /* We always support persistent connections in IMAP */
- connkeep(data->conn, "IMAP default");
-
/* Parse the URL options */
result = imap_parse_url_options(data->conn, imapc);
if(result)
BIT(premature);
};
+static bool multi_conn_should_close(struct connectdata *conn,
+ struct Curl_easy *data,
+ bool premature)
+{
+ /* if conn->bits.close is TRUE, it means that the connection should be
+ closed in spite of everything else. */
+ if(conn->bits.close)
+ return TRUE;
+
+ /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
+ forced us to close this connection. This is ignored for requests taking
+ place in a NTLM/NEGOTIATE authentication handshake. */
+ if(data->set.reuse_forbid
+#ifdef USE_NTLM
+ && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
+ conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
+#endif
+#ifdef USE_SPNEGO
+ && !(conn->http_negotiate_state == GSS_AUTHRECV ||
+ conn->proxy_negotiate_state == GSS_AUTHRECV)
+#endif
+ )
+ return TRUE;
+
+ /* Unless this connection is for a "connect-only" transfer, it
+ * needs to be closed if the protocol handler does not support reuse. */
+ if(!data->set.connect_only && conn->handler &&
+ !(conn->handler->flags & PROTOPT_CONN_REUSE))
+ return TRUE;
+
+ /* if premature is TRUE, it means this connection was said to be DONE before
+ the entire request operation is complete and thus we cannot know in what
+ state it is for reusing, so we are forced to close it. In a perfect world
+ we can add code that keep track of if we really must close it here or not,
+ but currently we have no such detail knowledge. */
+ if(premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))
+ return TRUE;
+
+ return FALSE;
+}
+
static void multi_done_locked(struct connectdata *conn,
struct Curl_easy *data,
void *userdata)
Curl_resolv_unlink(data, &data->state.dns[1]);
Curl_dnscache_prune(data);
- /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
- forced us to close this connection. This is ignored for requests taking
- place in a NTLM/NEGOTIATE authentication handshake
-
- if conn->bits.close is TRUE, it means that the connection should be
- closed in spite of all our efforts to be nice, due to protocol
- restrictions in our or the server's end
-
- if premature is TRUE, it means this connection was said to be DONE before
- the entire request operation is complete and thus we cannot know in what
- state it is for reusing, so we are forced to close it. In a perfect world
- we can add code that keep track of if we really must close it here or not,
- but currently we have no such detail knowledge.
- */
-
- if((data->set.reuse_forbid
-#ifdef USE_NTLM
- && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
- conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
-#endif
-#ifdef USE_SPNEGO
- && !(conn->http_negotiate_state == GSS_AUTHRECV ||
- conn->proxy_negotiate_state == GSS_AUTHRECV)
-#endif
- ) || conn->bits.close
- || (mdctx->premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
+ if(multi_conn_should_close(conn, data, mdctx->premature)) {
#ifndef CURL_DISABLE_VERBOSE_STRINGS
CURL_TRC_M(data, "multi_done, terminating conn #%" FMT_OFF_T " to %s:%d, "
"forbid=%d, close=%d, premature=%d, conn_multiplex=%d",
}
if(data->set.connect_only && !data->set.connect_only_ws) {
- /* keep connection open for application to use the socket */
- connkeep(data->conn, "CONNECT_ONLY");
multistate(data, MSTATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
}
PORT_LDAP, /* defport */
CURLPROTO_LDAP, /* protocol */
CURLPROTO_LDAP, /* family */
- PROTOPT_SSL_REUSE /* flags */
+ PROTOPT_SSL_REUSE | /* flags */
+ PROTOPT_CONN_REUSE
};
#ifdef USE_SSL
PORT_LDAPS, /* defport */
CURLPROTO_LDAPS, /* protocol */
CURLPROTO_LDAP, /* family */
- PROTOPT_SSL /* flags */
+ PROTOPT_SSL | /* flags */
+ PROTOPT_CONN_REUSE
};
#endif
if(!li)
return CURLE_FAILED_INIT;
- connkeep(conn, "OpenLDAP do");
infof(data, "LDAP local: %s", data->state.url);
CURLPROTO_POP3, /* protocol */
CURLPROTO_POP3, /* family */
PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
- PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE
+ PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE |
+ PROTOPT_CONN_REUSE
};
#ifdef USE_SSL
PORT_POP3S, /* defport */
CURLPROTO_POP3S, /* protocol */
CURLPROTO_POP3, /* family */
- PROTOPT_CLOSEACTION | PROTOPT_SSL
- | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
+ PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS |
+ PROTOPT_CONN_REUSE
};
#endif
if(!pop3c)
return CURLE_FAILED_INIT;
- /* We always support persistent connections in POP3 */
- connkeep(conn, "POP3 default");
-
PINGPONG_SETUP(pp, pop3_statemachine, pop3_endofresp);
/* Set the default preferred authentication type and mechanism */
PORT_RTSP, /* defport */
CURLPROTO_RTSP, /* protocol */
CURLPROTO_RTSP, /* family */
- PROTOPT_NONE /* flags */
+ PROTOPT_CONN_REUSE /* flags */
};
#define MAX_RTP_BUFFERSIZE 1000000 /* arbitrary */
PORT_SMB, /* defport */
CURLPROTO_SMB, /* protocol */
CURLPROTO_SMB, /* family */
- PROTOPT_NONE /* flags */
+ PROTOPT_CONN_REUSE /* flags */
};
#ifdef USE_SSL
PORT_SMBS, /* defport */
CURLPROTO_SMBS, /* protocol */
CURLPROTO_SMB, /* family */
- PROTOPT_SSL /* flags */
+ PROTOPT_SSL | PROTOPT_CONN_REUSE /* flags */
};
#endif
if(!smbc->send_buf)
return CURLE_OUT_OF_MEMORY;
- /* Multiple requests are allowed with this connection */
- connkeep(conn, "SMB default");
-
/* Parse the username, domain, and password */
slash = strchr(conn->user, '/');
if(!slash)
CURLPROTO_SMTP, /* protocol */
CURLPROTO_SMTP, /* family */
PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
- PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE
+ PROTOPT_URLOPTIONS | PROTOPT_SSL_REUSE |
+ PROTOPT_CONN_REUSE
};
#ifdef USE_SSL
PORT_SMTPS, /* defport */
CURLPROTO_SMTPS, /* protocol */
CURLPROTO_SMTP, /* family */
- PROTOPT_CLOSEACTION | PROTOPT_SSL
- | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
+ PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS |
+ PROTOPT_CONN_REUSE
};
#endif
if(!smtpc)
return CURLE_FAILED_INIT;
- /* We always support persistent connections in SMTP */
- connkeep(data->conn, "SMTP default");
-
PINGPONG_SETUP(&smtpc->pp, smtp_pp_statemachine, smtp_endofresp);
/* Initialize the SASL storage */
conn->connection_id = -1; /* no ID */
conn->remote_port = -1; /* unknown at this point */
- /* Default protocol-independent behavior does not support persistent
- connections, so we set this to force-close. Protocols that support
- this need to set this to FALSE in their "curl_do" functions. */
- connclose(conn, "Default to force-close");
-
/* Store creation time to help future close decision making */
conn->created = curlx_now();
#ifdef HAVE_GSSAPI
conn->gssapi_delegation = data->set.gssapi_delegation;
#endif
+ DEBUGF(infof(data, "alloc connection, bits.close=%d", conn->bits.close));
return conn;
error:
int port;
CURLcode result;
+ DEBUGF(infof(data, "setup connection, bits.close=%d", conn->bits.close));
if(conn->handler->setup_connection) {
result = conn->handler->setup_connection(data, conn);
if(result)
return result;
}
+ DEBUGF(infof(data, "setup connection, bits.close=%d", conn->bits.close));
/* Now create the destination name */
#ifndef CURL_DISABLE_PROXY
/* We have decided that we want a new connection. However, we may not
be able to do that if we have reached the limit of how many
connections we are allowed to open. */
+ DEBUGF(infof(data, "new connection, bits.close=%d", conn->bits.close));
if(conn->handler->flags & PROTOPT_ALPN) {
/* The protocol wants it, so set the bits if enabled in the easy handle
#define PROTOPT_SSL_REUSE (1<<15) /* this protocol may reuse an existing
SSL connection in the same family
without having PROTOPT_SSL. */
+#define PROTOPT_CONN_REUSE (1<<16) /* this protocol can reuse connections */
#define CONNCHECK_NONE 0 /* No checks */
#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */
CURL_TRC_CF(data, cf, "peer verified");
cf->connected = TRUE;
*done = TRUE;
- connkeep(cf->conn, "HTTP/3 default");
}
}
CURL_TRC_CF(data, cf, "peer verified");
cf->connected = TRUE;
*done = TRUE;
- connkeep(cf->conn, "HTTP/3 default");
}
}
else {
stream->closed = TRUE;
stream->reset = TRUE;
stream->send_closed = TRUE;
- streamclose(cf->conn, "Reset of stream");
return result;
}
return CURLE_OK;
stream->closed = TRUE;
stream->reset = TRUE;
stream->send_closed = TRUE;
- streamclose(cf->conn, "Reset of stream");
break;
case QUICHE_H3_EVENT_FINISHED:
stream->resp_hds_complete = TRUE;
}
stream->closed = TRUE;
- streamclose(cf->conn, "End of stream");
break;
case QUICHE_H3_EVENT_GOAWAY:
}
cf->connected = TRUE;
*done = TRUE;
- connkeep(cf->conn, "HTTP/3 default");
}
}
else if(quiche_conn_is_draining(ctx->qconn)) {
PORT_SSH, /* defport */
CURLPROTO_SCP, /* protocol */
CURLPROTO_SCP, /* family */
- PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
+ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
+ PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
};
/*
PORT_SSH, /* defport */
CURLPROTO_SFTP, /* protocol */
CURLPROTO_SFTP, /* family */
- PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
- | PROTOPT_NOURLQUERY /* flags */
+ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
+ PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
};
static CURLcode sftp_error_to_CURLE(int err)
if(!sshc || !ssh)
return CURLE_FAILED_INIT;
- /* We default to persistent connections. We set this already in this connect
- function to make the reuse checks properly be able to check this bit. */
- connkeep(conn, "SSH default");
-
if(conn->handler->protocol & CURLPROTO_SCP) {
conn->recv[FIRSTSOCKET] = scp_recv;
conn->send[FIRSTSOCKET] = scp_send;
PORT_SSH, /* defport */
CURLPROTO_SCP, /* protocol */
CURLPROTO_SCP, /* family */
- PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
- | PROTOPT_NOURLQUERY /* flags */
+ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
+ PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
};
PORT_SSH, /* defport */
CURLPROTO_SFTP, /* protocol */
CURLPROTO_SFTP, /* family */
- PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
- | PROTOPT_NOURLQUERY /* flags */
+ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION | /* flags */
+ PROTOPT_NOURLQUERY | PROTOPT_CONN_REUSE
};
static void
if(!sshc)
return CURLE_FAILED_INIT;
- /* We default to persistent connections. We set this already in this connect
- function to make the reuse checks properly be able to check this bit. */
- connkeep(conn, "SSH default");
-
infof(data, "User: '%s'", conn->user);
#ifdef CURL_LIBSSH2_DEBUG
infof(data, "Password: %s", conn->passwd);
char error_buffer[256];
unsigned long sslerror;
int buffsize;
- struct connectdata *conn = cf->conn;
struct ssl_connect_data *connssl = cf->ctx;
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
CURLcode result = CURLE_OK;
if(cf->sockindex == FIRSTSOCKET)
/* mark the connection for close if it is indeed the control
connection */
- connclose(conn, "TLS close_notify");
+ CURL_TRC_CF(data, cf, "TLS close_notify");
break;
case SSL_ERROR_WANT_READ:
connssl->io_need = CURL_SSL_IO_NEED_RECV;