|
| 1 | +From 58384112815014d94d5b35ddbe4b96b033224b81 Mon Sep 17 00:00:00 2001 |
| 2 | +From: AllSpark <allspark@microsoft.com> |
| 3 | +Date: Wed, 8 Jul 2026 11:01:50 +0000 |
| 4 | +Subject: [PATCH] http2: remove stream dependency tracking |
| 5 | + |
| 6 | +Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> |
| 7 | +Upstream-reference: AI Backport of https://github.com/curl/curl/commit/bfbff7852f050232edd3e5ca.patch |
| 8 | +--- |
| 9 | + docs/libcurl/curl_easy_setopt.md | 5 +- |
| 10 | + docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md | 8 ++ |
| 11 | + docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md | 8 ++ |
| 12 | + docs/libcurl/symbols-in-versions | 4 +- |
| 13 | + include/curl/curl.h | 6 +- |
| 14 | + lib/http2.c | 18 ++--- |
| 15 | + lib/setopt.c | 9 +- |
| 16 | + lib/url.c | 96 ------------------------- |
| 17 | + lib/urldata.h | 8 -- |
| 18 | + 9 files changed, 34 insertions(+), 128 deletions(-) |
| 19 | + |
| 20 | +diff --git a/docs/libcurl/curl_easy_setopt.md b/docs/libcurl/curl_easy_setopt.md |
| 21 | +index e0fe95c..73e240d 100644 |
| 22 | +--- a/docs/libcurl/curl_easy_setopt.md |
| 23 | ++++ b/docs/libcurl/curl_easy_setopt.md |
| 24 | +@@ -1146,11 +1146,12 @@ Redirect stderr to another stream. See CURLOPT_STDERR(3) |
| 25 | + |
| 26 | + ## CURLOPT_STREAM_DEPENDS |
| 27 | + |
| 28 | +-This HTTP/2 stream depends on another. See CURLOPT_STREAM_DEPENDS(3) |
| 29 | ++**Deprecated option** This HTTP/2 stream depends on another. See |
| 30 | ++CURLOPT_STREAM_DEPENDS(3) |
| 31 | + |
| 32 | + ## CURLOPT_STREAM_DEPENDS_E |
| 33 | + |
| 34 | +-This HTTP/2 stream depends on another exclusively. See |
| 35 | ++**Deprecated option** This HTTP/2 stream depends on another exclusively. See |
| 36 | + CURLOPT_STREAM_DEPENDS_E(3) |
| 37 | + |
| 38 | + ## CURLOPT_STREAM_WEIGHT |
| 39 | +diff --git a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md |
| 40 | +index 1429de1..4fc90b8 100644 |
| 41 | +--- a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md |
| 42 | ++++ b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md |
| 43 | +@@ -44,6 +44,10 @@ an error. It must be another easy handle, and it also needs to be a handle of |
| 44 | + a transfer that is about to be sent over the same HTTP/2 connection for this |
| 45 | + option to have an actual effect. |
| 46 | + |
| 47 | ++Since version 8.21.0 setting this option no longer has an effect. HTTP/2 |
| 48 | ++stream dependencies were introduced in RFC 7540 and then later deprecated |
| 49 | ++in RFC 9113. |
| 50 | ++ |
| 51 | + # DEFAULT |
| 52 | + |
| 53 | + NULL |
| 54 | +@@ -69,6 +73,10 @@ int main(void) |
| 55 | + } |
| 56 | + ~~~ |
| 57 | + |
| 58 | ++# DEPRECATED |
| 59 | ++ |
| 60 | ++Deprecated since 8.21.0. |
| 61 | ++ |
| 62 | + # %AVAILABILITY% |
| 63 | + |
| 64 | + # RETURN VALUE |
| 65 | +diff --git a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md |
| 66 | +index bddfead..0e85b72 100644 |
| 67 | +--- a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md |
| 68 | ++++ b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md |
| 69 | +@@ -47,6 +47,10 @@ an error. It must be another easy handle, and it also needs to be a handle of |
| 70 | + a transfer that is about to be sent over the same HTTP/2 connection for this |
| 71 | + option to have an actual effect. |
| 72 | + |
| 73 | ++Since version 8.21.0 setting this option no longer has an effect. HTTP/2 |
| 74 | ++stream dependencies were introduced in RFC 7540 and then later deprecated |
| 75 | ++in RFC 9113. |
| 76 | ++ |
| 77 | + # DEFAULT |
| 78 | + |
| 79 | + NULL |
| 80 | +@@ -72,6 +76,10 @@ int main(void) |
| 81 | + } |
| 82 | + ~~~ |
| 83 | + |
| 84 | ++# DEPRECATED |
| 85 | ++ |
| 86 | ++Deprecated since 8.21.0. |
| 87 | ++ |
| 88 | + # %AVAILABILITY% |
| 89 | + |
| 90 | + # RETURN VALUE |
| 91 | +diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions |
| 92 | +index ddda26d..b56527b 100644 |
| 93 | +--- a/docs/libcurl/symbols-in-versions |
| 94 | ++++ b/docs/libcurl/symbols-in-versions |
| 95 | +@@ -858,8 +858,8 @@ CURLOPT_SSLKEYPASSWD 7.9.3 7.17.0 |
| 96 | + CURLOPT_SSLKEYTYPE 7.9.3 |
| 97 | + CURLOPT_SSLVERSION 7.1 |
| 98 | + CURLOPT_STDERR 7.1 |
| 99 | +-CURLOPT_STREAM_DEPENDS 7.46.0 |
| 100 | +-CURLOPT_STREAM_DEPENDS_E 7.46.0 |
| 101 | ++CURLOPT_STREAM_DEPENDS 7.46.0 8.21.0 |
| 102 | ++CURLOPT_STREAM_DEPENDS_E 7.46.0 8.21.0 |
| 103 | + CURLOPT_STREAM_WEIGHT 7.46.0 |
| 104 | + CURLOPT_SUPPRESS_CONNECT_HEADERS 7.54.0 |
| 105 | + CURLOPT_TCP_FASTOPEN 7.49.0 |
| 106 | +diff --git a/include/curl/curl.h b/include/curl/curl.h |
| 107 | +index 1883558..8e04952 100644 |
| 108 | +--- a/include/curl/curl.h |
| 109 | ++++ b/include/curl/curl.h |
| 110 | +@@ -1960,10 +1960,12 @@ typedef enum { |
| 111 | + CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239), |
| 112 | + |
| 113 | + /* Set stream dependency on another CURL handle */ |
| 114 | +- CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240), |
| 115 | ++ CURLOPTDEPRECATED(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240, |
| 116 | ++ 8.21.0, "Has no function"), |
| 117 | + |
| 118 | + /* Set E-xclusive stream dependency on another CURL handle */ |
| 119 | +- CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241), |
| 120 | ++ CURLOPTDEPRECATED(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241, |
| 121 | ++ 8.21.0, "Has no function"), |
| 122 | + |
| 123 | + /* Do not send any tftp option requests to the server */ |
| 124 | + CURLOPT(CURLOPT_TFTP_NO_OPTIONS, CURLOPTTYPE_LONG, 242), |
| 125 | +diff --git a/lib/http2.c b/lib/http2.c |
| 126 | +index ef29686..2871c3d 100644 |
| 127 | +--- a/lib/http2.c |
| 128 | ++++ b/lib/http2.c |
| 129 | +@@ -1872,16 +1872,12 @@ static int sweight_in_effect(const struct Curl_easy *data) |
| 130 | + * struct. |
| 131 | + */ |
| 132 | + |
| 133 | +-static void h2_pri_spec(struct cf_h2_ctx *ctx, |
| 134 | +- struct Curl_easy *data, |
| 135 | ++static void h2_pri_spec(struct Curl_easy *data, |
| 136 | + nghttp2_priority_spec *pri_spec) |
| 137 | + { |
| 138 | + struct Curl_data_priority *prio = &data->set.priority; |
| 139 | +- struct h2_stream_ctx *depstream = H2_STREAM_CTX(ctx, prio->parent); |
| 140 | +- int32_t depstream_id = depstream ? depstream->id : 0; |
| 141 | +- nghttp2_priority_spec_init(pri_spec, depstream_id, |
| 142 | +- sweight_wanted(data), |
| 143 | +- data->set.priority.exclusive); |
| 144 | ++ nghttp2_priority_spec_init(pri_spec, 0, |
| 145 | ++ sweight_wanted(data), FALSE); |
| 146 | + data->state.priority = *prio; |
| 147 | + } |
| 148 | + |
| 149 | +@@ -1899,13 +1895,11 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, |
| 150 | + int rv = 0; |
| 151 | + |
| 152 | + if(stream && stream->id > 0 && |
| 153 | +- ((sweight_wanted(data) != sweight_in_effect(data)) || |
| 154 | +- (data->set.priority.exclusive != data->state.priority.exclusive) || |
| 155 | +- (data->set.priority.parent != data->state.priority.parent)) ) { |
| 156 | ++ (sweight_wanted(data) != sweight_in_effect(data))) { |
| 157 | + /* send new weight and/or dependency */ |
| 158 | + nghttp2_priority_spec pri_spec; |
| 159 | + |
| 160 | +- h2_pri_spec(ctx, data, &pri_spec); |
| 161 | ++ h2_pri_spec(data, &pri_spec); |
| 162 | + CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id); |
| 163 | + DEBUGASSERT(stream->id != -1); |
| 164 | + rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, |
| 165 | +@@ -2210,7 +2205,7 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream, |
| 166 | + goto out; |
| 167 | + } |
| 168 | + |
| 169 | +- h2_pri_spec(ctx, data, &pri_spec); |
| 170 | ++ h2_pri_spec(data, &pri_spec); |
| 171 | + if(!nghttp2_session_check_request_allowed(ctx->h2)) |
| 172 | + CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)"); |
| 173 | + |
| 174 | +diff --git a/lib/setopt.c b/lib/setopt.c |
| 175 | +index 1ab0d1e..6b8cbb3 100644 |
| 176 | +--- a/lib/setopt.c |
| 177 | ++++ b/lib/setopt.c |
| 178 | +@@ -1652,13 +1652,10 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, |
| 179 | + |
| 180 | + #ifdef USE_HTTP2 |
| 181 | + case CURLOPT_STREAM_DEPENDS: |
| 182 | +- case CURLOPT_STREAM_DEPENDS_E: { |
| 183 | +- struct Curl_easy *dep = va_arg(param, struct Curl_easy *); |
| 184 | +- if(!dep || GOOD_EASY_HANDLE(dep)) |
| 185 | +- return Curl_data_priority_add_child(dep, data, |
| 186 | +- option == CURLOPT_STREAM_DEPENDS_E); |
| 187 | ++ case CURLOPT_STREAM_DEPENDS_E: |
| 188 | ++ /* not doing stream dependencies any longer, but accept options |
| 189 | ++ * for backward compatibility */ |
| 190 | + break; |
| 191 | +- } |
| 192 | + #endif |
| 193 | + |
| 194 | + default: |
| 195 | +diff --git a/lib/url.c b/lib/url.c |
| 196 | +index cd8dbcc..7923485 100644 |
| 197 | +--- a/lib/url.c |
| 198 | ++++ b/lib/url.c |
| 199 | +@@ -130,12 +130,6 @@ |
| 200 | + #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) |
| 201 | + #endif |
| 202 | + |
| 203 | +-#ifdef USE_NGHTTP2 |
| 204 | +-static void data_priority_cleanup(struct Curl_easy *data); |
| 205 | +-#else |
| 206 | +-#define data_priority_cleanup(x) |
| 207 | +-#endif |
| 208 | +- |
| 209 | + /* Some parts of the code (e.g. chunked encoding) assume this buffer has at |
| 210 | + * more than just a few bytes to play with. Do not let it become too small or |
| 211 | + * bad things will happen. |
| 212 | +@@ -298,7 +292,6 @@ CURLcode Curl_close(struct Curl_easy **datap) |
| 213 | + Curl_resolver_cancel(data); |
| 214 | + Curl_resolver_cleanup(data->state.async.resolver); |
| 215 | + |
| 216 | +- data_priority_cleanup(data); |
| 217 | + |
| 218 | + /* No longer a dirty share, if it exists */ |
| 219 | + if(data->share) { |
| 220 | +@@ -3957,96 +3949,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) |
| 221 | + |
| 222 | + #if defined(USE_HTTP2) || defined(USE_HTTP3) |
| 223 | + |
| 224 | +-#ifdef USE_NGHTTP2 |
| 225 | +- |
| 226 | +-static void priority_remove_child(struct Curl_easy *parent, |
| 227 | +- struct Curl_easy *child) |
| 228 | +-{ |
| 229 | +- struct Curl_data_prio_node **pnext = &parent->set.priority.children; |
| 230 | +- struct Curl_data_prio_node *pnode = parent->set.priority.children; |
| 231 | +- |
| 232 | +- DEBUGASSERT(child->set.priority.parent == parent); |
| 233 | +- while(pnode && pnode->data != child) { |
| 234 | +- pnext = &pnode->next; |
| 235 | +- pnode = pnode->next; |
| 236 | +- } |
| 237 | +- |
| 238 | +- DEBUGASSERT(pnode); |
| 239 | +- if(pnode) { |
| 240 | +- *pnext = pnode->next; |
| 241 | +- free(pnode); |
| 242 | +- } |
| 243 | +- |
| 244 | +- child->set.priority.parent = 0; |
| 245 | +- child->set.priority.exclusive = FALSE; |
| 246 | +-} |
| 247 | +- |
| 248 | +-CURLcode Curl_data_priority_add_child(struct Curl_easy *parent, |
| 249 | +- struct Curl_easy *child, |
| 250 | +- bool exclusive) |
| 251 | +-{ |
| 252 | +- if(child->set.priority.parent) { |
| 253 | +- priority_remove_child(child->set.priority.parent, child); |
| 254 | +- } |
| 255 | +- |
| 256 | +- if(parent) { |
| 257 | +- struct Curl_data_prio_node **tail; |
| 258 | +- struct Curl_data_prio_node *pnode; |
| 259 | +- |
| 260 | +- pnode = calloc(1, sizeof(*pnode)); |
| 261 | +- if(!pnode) |
| 262 | +- return CURLE_OUT_OF_MEMORY; |
| 263 | +- pnode->data = child; |
| 264 | +- |
| 265 | +- if(parent->set.priority.children && exclusive) { |
| 266 | +- /* exclusive: move all existing children underneath the new child */ |
| 267 | +- struct Curl_data_prio_node *node = parent->set.priority.children; |
| 268 | +- while(node) { |
| 269 | +- node->data->set.priority.parent = child; |
| 270 | +- node = node->next; |
| 271 | +- } |
| 272 | +- |
| 273 | +- tail = &child->set.priority.children; |
| 274 | +- while(*tail) |
| 275 | +- tail = &(*tail)->next; |
| 276 | +- |
| 277 | +- DEBUGASSERT(!*tail); |
| 278 | +- *tail = parent->set.priority.children; |
| 279 | +- parent->set.priority.children = 0; |
| 280 | +- } |
| 281 | +- |
| 282 | +- tail = &parent->set.priority.children; |
| 283 | +- while(*tail) { |
| 284 | +- (*tail)->data->set.priority.exclusive = FALSE; |
| 285 | +- tail = &(*tail)->next; |
| 286 | +- } |
| 287 | +- |
| 288 | +- DEBUGASSERT(!*tail); |
| 289 | +- *tail = pnode; |
| 290 | +- } |
| 291 | +- |
| 292 | +- child->set.priority.parent = parent; |
| 293 | +- child->set.priority.exclusive = exclusive; |
| 294 | +- return CURLE_OK; |
| 295 | +-} |
| 296 | +- |
| 297 | +-#endif /* USE_NGHTTP2 */ |
| 298 | +- |
| 299 | +-#ifdef USE_NGHTTP2 |
| 300 | +-static void data_priority_cleanup(struct Curl_easy *data) |
| 301 | +-{ |
| 302 | +- while(data->set.priority.children) { |
| 303 | +- struct Curl_easy *tmp = data->set.priority.children->data; |
| 304 | +- priority_remove_child(data, tmp); |
| 305 | +- if(data->set.priority.parent) |
| 306 | +- Curl_data_priority_add_child(data->set.priority.parent, tmp, FALSE); |
| 307 | +- } |
| 308 | +- |
| 309 | +- if(data->set.priority.parent) |
| 310 | +- priority_remove_child(data->set.priority.parent, data); |
| 311 | +-} |
| 312 | +-#endif |
| 313 | + |
| 314 | + void Curl_data_priority_clear_state(struct Curl_easy *data) |
| 315 | + { |
| 316 | + memset(&data->state.priority, 0, sizeof(data->state.priority)); |
| 317 | +diff --git a/lib/urldata.h b/lib/urldata.h |
| 318 | +index 9d4c33a..f12958d 100644 |
| 319 | +--- a/lib/urldata.h |
| 320 | ++++ b/lib/urldata.h |
| 321 | +@@ -1145,15 +1145,7 @@ struct Curl_data_prio_node { |
| 322 | + * TODO: we need to adapt it to the new priority scheme as defined in RFC 9218 |
| 323 | + */ |
| 324 | + struct Curl_data_priority { |
| 325 | +-#ifdef USE_NGHTTP2 |
| 326 | +- /* tree like dependencies only implemented in nghttp2 */ |
| 327 | +- struct Curl_easy *parent; |
| 328 | +- struct Curl_data_prio_node *children; |
| 329 | +-#endif |
| 330 | + int weight; |
| 331 | +-#ifdef USE_NGHTTP2 |
| 332 | +- BIT(exclusive); |
| 333 | +-#endif |
| 334 | + }; |
| 335 | + |
| 336 | + /* Timers */ |
| 337 | +-- |
| 338 | +2.45.4 |
| 339 | + |
0 commit comments