mirror of
https://github.com/moparisthebest/curl
synced 2024-12-23 16:48:49 -05:00
http2: several cleanups
- separate easy handle from connections better - added asserts on a number of places - added sanity check of pipelines for debug builds Closes #2751
This commit is contained in:
parent
73af7bcd61
commit
7b9bc96c77
@ -131,7 +131,7 @@ CURLcode Curl_async_resolved(struct connectdata *conn,
|
|||||||
if(result)
|
if(result)
|
||||||
/* We're not allowed to return failure with memory left allocated
|
/* We're not allowed to return failure with memory left allocated
|
||||||
in the connectdata struct, free those here */
|
in the connectdata struct, free those here */
|
||||||
Curl_disconnect(conn->data, conn, FALSE); /* close the connection */
|
Curl_disconnect(conn->data, conn, TRUE); /* close the connection */
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
11
lib/http.c
11
lib/http.c
@ -158,18 +158,20 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
|
|||||||
/* allocate the HTTP-specific struct for the Curl_easy, only to survive
|
/* allocate the HTTP-specific struct for the Curl_easy, only to survive
|
||||||
during this request */
|
during this request */
|
||||||
struct HTTP *http;
|
struct HTTP *http;
|
||||||
DEBUGASSERT(conn->data->req.protop == NULL);
|
struct Curl_easy *data = conn->data;
|
||||||
|
DEBUGASSERT(data->req.protop == NULL);
|
||||||
|
|
||||||
http = calloc(1, sizeof(struct HTTP));
|
http = calloc(1, sizeof(struct HTTP));
|
||||||
if(!http)
|
if(!http)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
Curl_mime_initpart(&http->form, conn->data);
|
Curl_mime_initpart(&http->form, conn->data);
|
||||||
conn->data->req.protop = http;
|
data->req.protop = http;
|
||||||
|
|
||||||
|
if(!CONN_INUSE(conn))
|
||||||
|
/* if not alredy multi-using, setup connection details */
|
||||||
Curl_http2_setup_conn(conn);
|
Curl_http2_setup_conn(conn);
|
||||||
Curl_http2_setup_req(conn->data);
|
Curl_http2_setup_req(data);
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1913,6 +1915,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
|||||||
}
|
}
|
||||||
|
|
||||||
http = data->req.protop;
|
http = data->req.protop;
|
||||||
|
DEBUGASSERT(http);
|
||||||
|
|
||||||
if(!data->state.this_is_a_follow) {
|
if(!data->state.this_is_a_follow) {
|
||||||
/* Free to avoid leaking memory on multiple requests*/
|
/* Free to avoid leaking memory on multiple requests*/
|
||||||
|
@ -154,6 +154,11 @@ static void http2_stream_free(struct HTTP *http)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disconnects *a* connection used for HTTP/2. It might be an old one from the
|
||||||
|
* connection cache and not the "main" one. Don't touch the easy handle!
|
||||||
|
*/
|
||||||
|
|
||||||
static CURLcode http2_disconnect(struct connectdata *conn,
|
static CURLcode http2_disconnect(struct connectdata *conn,
|
||||||
bool dead_connection)
|
bool dead_connection)
|
||||||
{
|
{
|
||||||
@ -164,8 +169,6 @@ static CURLcode http2_disconnect(struct connectdata *conn,
|
|||||||
|
|
||||||
nghttp2_session_del(c->h2);
|
nghttp2_session_del(c->h2);
|
||||||
Curl_safefree(c->inbuf);
|
Curl_safefree(c->inbuf);
|
||||||
http2_stream_free(conn->data->req.protop);
|
|
||||||
conn->data->state.drain = 0;
|
|
||||||
|
|
||||||
H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
|
H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
|
||||||
|
|
||||||
@ -520,6 +523,7 @@ static int push_promise(struct Curl_easy *data,
|
|||||||
if(rv) {
|
if(rv) {
|
||||||
/* denied, kill off the new handle again */
|
/* denied, kill off the new handle again */
|
||||||
http2_stream_free(newhandle->req.protop);
|
http2_stream_free(newhandle->req.protop);
|
||||||
|
newhandle->req.protop = NULL;
|
||||||
(void)Curl_close(newhandle);
|
(void)Curl_close(newhandle);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@ -535,6 +539,7 @@ static int push_promise(struct Curl_easy *data,
|
|||||||
if(rc) {
|
if(rc) {
|
||||||
infof(data, "failed to add handle to multi\n");
|
infof(data, "failed to add handle to multi\n");
|
||||||
http2_stream_free(newhandle->req.protop);
|
http2_stream_free(newhandle->req.protop);
|
||||||
|
newhandle->req.protop = NULL;
|
||||||
Curl_close(newhandle);
|
Curl_close(newhandle);
|
||||||
rv = 1;
|
rv = 1;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -65,7 +65,7 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
|
|||||||
#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
|
#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
|
||||||
#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL
|
#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL
|
||||||
#define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL
|
#define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL
|
||||||
#define Curl_http2_setup_conn(x)
|
#define Curl_http2_setup_conn(x) Curl_nop_stmt
|
||||||
#define Curl_http2_setup_req(x)
|
#define Curl_http2_setup_req(x)
|
||||||
#define Curl_http2_init_state(x)
|
#define Curl_http2_init_state(x)
|
||||||
#define Curl_http2_init_userset(x)
|
#define Curl_http2_init_userset(x)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
|
* Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
|
||||||
* Copyright (C) 2013 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 2013 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -110,8 +110,8 @@ CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
|
|||||||
pipeline = &conn->send_pipe;
|
pipeline = &conn->send_pipe;
|
||||||
|
|
||||||
result = addHandleToPipeline(handle, pipeline);
|
result = addHandleToPipeline(handle, pipeline);
|
||||||
|
if((conn->bundle->multiuse == BUNDLE_PIPELINING) &&
|
||||||
if(pipeline == &conn->send_pipe && sendhead != conn->send_pipe.head) {
|
(pipeline == &conn->send_pipe && sendhead != conn->send_pipe.head)) {
|
||||||
/* this is a new one as head, expire it */
|
/* this is a new one as head, expire it */
|
||||||
Curl_pipeline_leave_write(conn); /* not in use yet */
|
Curl_pipeline_leave_write(conn); /* not in use yet */
|
||||||
Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
|
Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
|
||||||
|
77
lib/url.c
77
lib/url.c
@ -127,7 +127,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
|
|||||||
|
|
||||||
static void conn_free(struct connectdata *conn);
|
static void conn_free(struct connectdata *conn);
|
||||||
static void free_fixed_hostname(struct hostname *host);
|
static void free_fixed_hostname(struct hostname *host);
|
||||||
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
|
|
||||||
static CURLcode parse_url_login(struct Curl_easy *data,
|
static CURLcode parse_url_login(struct Curl_easy *data,
|
||||||
struct connectdata *conn,
|
struct connectdata *conn,
|
||||||
char **userptr, char **passwdptr,
|
char **userptr, char **passwdptr,
|
||||||
@ -750,7 +749,7 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
|
|||||||
return CURLE_OK; /* this is closed and fine already */
|
return CURLE_OK; /* this is closed and fine already */
|
||||||
|
|
||||||
if(!data) {
|
if(!data) {
|
||||||
DEBUGF(fprintf(stderr, "DISCONNECT without easy handle, ignoring\n"));
|
DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n"));
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,9 +757,8 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
|
|||||||
* If this connection isn't marked to force-close, leave it open if there
|
* If this connection isn't marked to force-close, leave it open if there
|
||||||
* are other users of it
|
* are other users of it
|
||||||
*/
|
*/
|
||||||
if(!conn->bits.close && CONN_INUSE(conn)) {
|
if(CONN_INUSE(conn) && !dead_connection) {
|
||||||
DEBUGF(fprintf(stderr, "Curl_disconnect when inuse: %d\n",
|
DEBUGF(infof(data, "Curl_disconnect when inuse: %d\n", CONN_INUSE(conn)));
|
||||||
CONN_INUSE(conn)));
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,14 +790,7 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
|
|||||||
|
|
||||||
Curl_ssl_close(conn, FIRSTSOCKET);
|
Curl_ssl_close(conn, FIRSTSOCKET);
|
||||||
|
|
||||||
/* Indicate to all handles on the pipe that we're dead */
|
|
||||||
if(Curl_pipeline_wanted(data->multi, CURLPIPE_ANY)) {
|
|
||||||
signalPipeClose(&conn->send_pipe, TRUE);
|
|
||||||
signalPipeClose(&conn->recv_pipe, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
conn_free(conn);
|
conn_free(conn);
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -888,6 +879,16 @@ static void Curl_printPipeline(struct curl_llist *pipeline)
|
|||||||
static struct Curl_easy* gethandleathead(struct curl_llist *pipeline)
|
static struct Curl_easy* gethandleathead(struct curl_llist *pipeline)
|
||||||
{
|
{
|
||||||
struct curl_llist_element *curr = pipeline->head;
|
struct curl_llist_element *curr = pipeline->head;
|
||||||
|
#ifdef DEBUGBUILD
|
||||||
|
{
|
||||||
|
struct curl_llist_element *p = pipeline->head;
|
||||||
|
while(p) {
|
||||||
|
struct Curl_easy *e = p->ptr;
|
||||||
|
DEBUGASSERT(GOOD_EASY_HANDLE(e));
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if(curr) {
|
if(curr) {
|
||||||
return (struct Curl_easy *) curr->ptr;
|
return (struct Curl_easy *) curr->ptr;
|
||||||
}
|
}
|
||||||
@ -920,33 +921,6 @@ void Curl_getoff_all_pipelines(struct Curl_easy *data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
|
|
||||||
{
|
|
||||||
struct curl_llist_element *curr;
|
|
||||||
|
|
||||||
if(!pipeline)
|
|
||||||
return;
|
|
||||||
|
|
||||||
curr = pipeline->head;
|
|
||||||
while(curr) {
|
|
||||||
struct curl_llist_element *next = curr->next;
|
|
||||||
struct Curl_easy *data = (struct Curl_easy *) curr->ptr;
|
|
||||||
|
|
||||||
#ifdef DEBUGBUILD /* debug-only code */
|
|
||||||
if(data->magic != CURLEASY_MAGIC_NUMBER) {
|
|
||||||
/* MAJOR BADNESS */
|
|
||||||
infof(data, "signalPipeClose() found BAAD easy handle\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(pipe_broke)
|
|
||||||
data->state.pipe_broke = TRUE;
|
|
||||||
Curl_multi_handlePipeBreak(data);
|
|
||||||
Curl_llist_remove(pipeline, curr, NULL);
|
|
||||||
curr = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
proxy_info_matches(const struct proxy_info* data,
|
proxy_info_matches(const struct proxy_info* data,
|
||||||
const struct proxy_info* needle)
|
const struct proxy_info* needle)
|
||||||
@ -2498,18 +2472,6 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
|
|||||||
{
|
{
|
||||||
const struct Curl_handler * p;
|
const struct Curl_handler * p;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
struct Curl_easy *data = conn->data;
|
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
Curl_free_request_state(data);
|
|
||||||
|
|
||||||
memset(&data->req, 0, sizeof(struct SingleRequest));
|
|
||||||
data->req.maxdownload = -1;
|
|
||||||
|
|
||||||
conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
|
conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
|
||||||
|
|
||||||
/* Perform setup complement if some. */
|
/* Perform setup complement if some. */
|
||||||
@ -4675,12 +4637,16 @@ CURLcode Curl_connect(struct Curl_easy *data,
|
|||||||
|
|
||||||
*asyncp = FALSE; /* assume synchronous resolves by default */
|
*asyncp = FALSE; /* assume synchronous resolves by default */
|
||||||
|
|
||||||
|
/* init the single-transfer specific data */
|
||||||
|
Curl_free_request_state(data);
|
||||||
|
memset(&data->req, 0, sizeof(struct SingleRequest));
|
||||||
|
data->req.maxdownload = -1;
|
||||||
|
|
||||||
/* call the stuff that needs to be called */
|
/* call the stuff that needs to be called */
|
||||||
result = create_conn(data, in_connect, asyncp);
|
result = create_conn(data, in_connect, asyncp);
|
||||||
|
|
||||||
if(!result) {
|
if(!result) {
|
||||||
/* no error */
|
if(CONN_INUSE(*in_connect))
|
||||||
if((*in_connect)->send_pipe.size || (*in_connect)->recv_pipe.size)
|
|
||||||
/* pipelining */
|
/* pipelining */
|
||||||
*protocol_done = TRUE;
|
*protocol_done = TRUE;
|
||||||
else if(!*asyncp) {
|
else if(!*asyncp) {
|
||||||
@ -4695,11 +4661,10 @@ CURLcode Curl_connect(struct Curl_easy *data,
|
|||||||
*in_connect = NULL;
|
*in_connect = NULL;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
else if(result && *in_connect) {
|
||||||
if(result && *in_connect) {
|
|
||||||
/* We're not allowed to return failure with memory left allocated in the
|
/* We're not allowed to return failure with memory left allocated in the
|
||||||
connectdata struct, free those here */
|
connectdata struct, free those here */
|
||||||
Curl_disconnect(data, *in_connect, FALSE);
|
Curl_disconnect(data, *in_connect, TRUE);
|
||||||
*in_connect = NULL; /* return a NULL */
|
*in_connect = NULL; /* return a NULL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,7 +786,7 @@ struct connectdata {
|
|||||||
other easy handle without careful consideration (== only for
|
other easy handle without careful consideration (== only for
|
||||||
pipelining/multiplexing) and it cannot be used by another multi
|
pipelining/multiplexing) and it cannot be used by another multi
|
||||||
handle! */
|
handle! */
|
||||||
#define CONN_INUSE(c) ((c)->send_pipe.size || (c)->recv_pipe.size)
|
#define CONN_INUSE(c) ((c)->send_pipe.size + (c)->recv_pipe.size)
|
||||||
|
|
||||||
/**** Fields set when inited and not modified again */
|
/**** Fields set when inited and not modified again */
|
||||||
long connection_id; /* Contains a unique number to make it easier to
|
long connection_id; /* Contains a unique number to make it easier to
|
||||||
|
Loading…
Reference in New Issue
Block a user