diff options
author | Daniel Stenberg <daniel@haxx.se> | 2020-07-16 00:24:29 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2020-07-16 00:24:29 +0200 |
commit | 954cd3eb482a00fda610ca64498d50db2b2e8298 (patch) | |
tree | 261374f3a3c9c158a42b0c3bfe33d5cb6bd18b78 | |
parent | 2f5d0e497e65aefd655a08e5ca96c70cc3123b40 (diff) | |
download | curl-954cd3eb482a00fda610ca64498d50db2b2e8298.tar.gz |
CURL_PUSH_ERROROUT: allow the push callback to fail the parent stream
... by adding support for a new dedicated return code.
Suggested-by: Jonathan Cardoso
Assisted-by: Erik Johansson
URL: https://curl.haxx.se/mail/lib-2020-06/0099.html
Closes #5636
-rw-r--r-- | docs/TODO | 8 | ||||
-rw-r--r-- | docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 | 3 | ||||
-rw-r--r-- | docs/libcurl/symbols-in-versions | 1 | ||||
-rw-r--r-- | include/curl/multi.h | 10 | ||||
-rw-r--r-- | lib/http2.c | 27 |
5 files changed, 28 insertions, 21 deletions
@@ -36,7 +36,6 @@ 1.17 Add support for IRIs 1.18 try next proxy if one doesn't work 1.20 SRV and URI DNS records - 1.21 Add return code to CURLMOPT_PUSHFUNCTION to fail the connection 1.22 CURLINFO_PAUSE_STATE 1.23 Offer API to flush the connection pool 1.24 TCP Fast Open for windows @@ -358,13 +357,6 @@ Offer support for resolving SRV and URI DNS records for libcurl to know which server to connect to for various protocols (including HTTP!). -1.21 Add return code to CURLMOPT_PUSHFUNCTION to fail the connection - - Allow the callback to return a value that would stop the entire operation, - like it can be done from most other callbacks. - - See https://curl.haxx.se/mail/lib-2020-06/0099.html - 1.22 CURLINFO_PAUSE_STATE Return information about the transfer's current pause state, in both diff --git a/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 b/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 index 241f47547..a80b2539f 100644 --- a/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 +++ b/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 @@ -86,6 +86,9 @@ the ownership of the CURL handle has been taken over by the application. .IP "CURL_PUSH_DENY (1)" The callback denies the stream and no data for this will reach the application, the easy handle will be destroyed by libcurl. +.IP "CURL_PUSH_ERROROUT (2)" +Returning this will reject the pushed stream and return an error back on the +parent stream making it get closed with an error. (Added in curl 7.72.0) .IP * All other return codes are reserved for future use. .SH DEFAULT diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index ca2865725..c0cdbdc04 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -892,6 +892,7 @@ CURL_PROGRESSFUNC_CONTINUE 7.68.0 CURL_PROGRESS_BAR 7.1.1 - 7.4.1 CURL_PROGRESS_STATS 7.1.1 - 7.4.1 CURL_PUSH_DENY 7.44.0 +CURL_PUSH_ERROROUT 7.72.0 CURL_PUSH_OK 7.44.0 CURL_READFUNC_ABORT 7.12.1 CURL_READFUNC_PAUSE 7.18.0 diff --git a/include/curl/multi.h b/include/curl/multi.h index 2e6bb72d6..b911ba92d 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -427,12 +427,14 @@ CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, * Name: curl_push_callback * * Desc: This callback gets called when a new stream is being pushed by the - * server. It approves or denies the new stream. + * server. It approves or denies the new stream. It can also decide + * to completely fail the connection. * - * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + * Returns: CURL_PUSH_OK, CURL_PUSH_DENY or CURL_PUSH_ERROROUT */ -#define CURL_PUSH_OK 0 -#define CURL_PUSH_DENY 1 +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 +#define CURL_PUSH_ERROROUT 2 /* added in 7.72.0 */ struct curl_pushheaders; /* forward declaration only */ diff --git a/lib/http2.c b/lib/http2.c index e81dc8d01..e4fa9b0b3 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -514,7 +514,7 @@ static int push_promise(struct Curl_easy *data, struct connectdata *conn, const nghttp2_push_promise *frame) { - int rv; + int rv; /* one of the CURL_PUSH_* defines */ H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n", frame->promised_stream_id)); if(data->multi->push_cb) { @@ -528,7 +528,7 @@ static int push_promise(struct Curl_easy *data, struct Curl_easy *newhandle = duphandle(data); if(!newhandle) { infof(data, "failed to duplicate handle\n"); - rv = 1; /* FAIL HARD */ + rv = CURL_PUSH_DENY; /* FAIL HARD */ goto fail; } @@ -541,13 +541,15 @@ static int push_promise(struct Curl_easy *data, if(!stream) { failf(data, "Internal NULL stream!\n"); (void)Curl_close(&newhandle); - rv = 1; + rv = CURL_PUSH_DENY; goto fail; } rv = set_transfer_url(newhandle, &heads); - if(rv) + if(rv) { + rv = CURL_PUSH_DENY; goto fail; + } Curl_set_in_callback(data, true); rv = data->multi->push_cb(data, newhandle, @@ -563,6 +565,7 @@ static int push_promise(struct Curl_easy *data, stream->push_headers_used = 0; if(rv) { + DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT)); /* denied, kill off the new handle again */ http2_stream_free(newhandle->req.protop); newhandle->req.protop = NULL; @@ -583,7 +586,7 @@ static int push_promise(struct Curl_easy *data, http2_stream_free(newhandle->req.protop); newhandle->req.protop = NULL; Curl_close(&newhandle); - rv = 1; + rv = CURL_PUSH_DENY; goto fail; } @@ -595,12 +598,13 @@ static int push_promise(struct Curl_easy *data, infof(data, "failed to set user_data for stream %d\n", frame->promised_stream_id); DEBUGASSERT(0); + rv = CURL_PUSH_DENY; goto fail; } } else { H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n")); - rv = 1; + rv = CURL_PUSH_DENY; } fail: return rv; @@ -737,11 +741,16 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, case NGHTTP2_PUSH_PROMISE: rv = push_promise(data_s, conn, &frame->push_promise); if(rv) { /* deny! */ - rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, + int h2; + DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT)); + h2 = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL); - if(nghttp2_is_fatal(rv)) { - return rv; + if(nghttp2_is_fatal(h2)) + return NGHTTP2_ERR_CALLBACK_FAILURE; + else if(rv == CURL_PUSH_ERROROUT) { + DEBUGF(infof(data_s, "Fail the parent stream (too)\n")); + return NGHTTP2_ERR_CALLBACK_FAILURE; } } break; |