Coverage Report

Created: 2026-10-22 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/ngh2_shim.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2)
27
#include <nghttp2/nghttp2.h>
28
29
#include "urldata.h"
30
#include "ngh2_shim.h"
31
32
33
bool Curl_ngh2_valid(struct curl_ngh2 *ngh2)
34
0
{
35
0
  return ngh2->s && !ngh2->fatal_rv;
36
0
}
37
38
bool Curl_ngh2_is_fatal(struct curl_ngh2 *ngh2, int rv)
39
0
{
40
0
  if(ngh2->fatal_rv)
41
0
    return TRUE;
42
0
  if(nghttp2_is_fatal(rv)) {
43
0
    ngh2->fatal_rv = rv;
44
0
    return TRUE;
45
0
  }
46
0
  return FALSE;
47
0
}
48
49
int Curl_ngh2_fatal(struct curl_ngh2 *ngh2)
50
0
{
51
0
  return ngh2->fatal_rv;
52
0
}
53
54
static int ngh2_check(struct curl_ngh2 *ngh2, int rv)
55
0
{
56
0
  if(nghttp2_is_fatal(rv))
57
0
    ngh2->fatal_rv = rv;
58
0
  return rv;
59
0
}
60
61
static int32_t ngh2_check32(struct curl_ngh2 *ngh2, int32_t rv)
62
0
{
63
0
  if((rv < 0) && nghttp2_is_fatal((int)rv))
64
0
    ngh2->fatal_rv = (int)rv;
65
0
  return rv;
66
0
}
67
68
static ssize_t ngh2_checks(struct curl_ngh2 *ngh2, ssize_t rv)
69
0
{
70
0
  if((rv < 0) && nghttp2_is_fatal((int)rv))
71
0
    ngh2->fatal_rv = (int)rv;
72
0
  return rv;
73
0
}
74
75
void Curl_ngh2_del(struct curl_ngh2 *ngh2)
76
0
{
77
0
  if(ngh2->s) {
78
0
    nghttp2_session_del(ngh2->s);
79
0
    ngh2->s = NULL;
80
0
  }
81
0
}
82
83
int Curl_ngh2_submit_settings(struct curl_ngh2 *ngh2,
84
                              uint8_t flags,
85
                              const nghttp2_settings_entry *iv,
86
                              size_t niv)
87
0
{
88
0
  if(ngh2->fatal_rv)
89
0
    return ngh2->fatal_rv;
90
0
  return ngh2_check(ngh2, nghttp2_submit_settings(ngh2->s, flags, iv, niv));
91
0
}
92
93
void *Curl_ngh2_session_get_stream_user_data(struct curl_ngh2 *ngh2,
94
                                             int32_t stream_id)
95
0
{
96
0
  if(ngh2->fatal_rv)
97
0
    return NULL;
98
0
  return nghttp2_session_get_stream_user_data(ngh2->s, stream_id);
99
0
}
100
101
int Curl_ngh2_session_set_stream_user_data(
102
  struct curl_ngh2 *ngh2, int32_t stream_id, void *stream_user_data)
103
0
{
104
0
  if(ngh2->fatal_rv)
105
0
    return ngh2->fatal_rv;
106
0
  return ngh2_check(ngh2,
107
0
    nghttp2_session_set_stream_user_data(
108
0
      ngh2->s, stream_id, stream_user_data));
109
0
}
110
111
uint32_t Curl_ngh2_session_get_remote_settings(
112
  struct curl_ngh2 *ngh2, nghttp2_settings_id id)
113
0
{
114
0
  if(!Curl_ngh2_valid(ngh2))
115
0
    return 0;
116
0
  return nghttp2_session_get_remote_settings(ngh2->s, id);
117
0
}
118
119
int32_t Curl_ngh2_session_get_stream_effective_local_window_size(
120
  struct curl_ngh2 *ngh2, int32_t stream_id)
121
0
{
122
0
  if(ngh2->fatal_rv)
123
0
    return 0;
124
0
  return nghttp2_session_get_stream_effective_local_window_size(
125
0
    ngh2->s, stream_id);
126
0
}
127
128
int32_t Curl_ngh2_session_get_local_window_size(
129
  struct curl_ngh2 *ngh2)
130
0
{
131
0
  if(ngh2->fatal_rv)
132
0
    return 0;
133
0
  return nghttp2_session_get_local_window_size(ngh2->s);
134
0
}
135
136
int32_t Curl_ngh2_session_get_stream_remote_window_size(
137
  struct curl_ngh2 *ngh2, int32_t stream_id)
138
0
{
139
0
  if(ngh2->fatal_rv)
140
0
    return 0;
141
0
  return nghttp2_session_get_stream_remote_window_size(ngh2->s, stream_id);
142
0
}
143
144
int32_t Curl_ngh2_session_get_remote_window_size(
145
  struct curl_ngh2 *ngh2)
146
0
{
147
0
  if(ngh2->fatal_rv)
148
0
    return 0;
149
0
  return nghttp2_session_get_remote_window_size(ngh2->s);
150
0
}
151
152
int Curl_ngh2_session_set_local_window_size(
153
  struct curl_ngh2 *ngh2, uint8_t flags,
154
  int32_t stream_id, int32_t window_size)
155
0
{
156
0
  if(ngh2->fatal_rv)
157
0
    return ngh2->fatal_rv;
158
0
  return ngh2_check(ngh2, nghttp2_session_set_local_window_size(
159
0
    ngh2->s, flags, stream_id, window_size));
160
0
}
161
162
int Curl_ngh2_submit_window_update(struct curl_ngh2 *ngh2,
163
  uint8_t flags,
164
  int32_t stream_id,
165
  int32_t window_size_increment)
166
0
{
167
0
  if(ngh2->fatal_rv)
168
0
    return ngh2->fatal_rv;
169
0
  return ngh2_check(ngh2, nghttp2_submit_window_update(
170
0
    ngh2->s, flags, stream_id, window_size_increment));
171
0
}
172
173
int Curl_ngh2_submit_rst_stream(
174
  struct curl_ngh2 *ngh2, uint8_t flags,
175
  int32_t stream_id, uint32_t error_code)
176
0
{
177
0
  if(ngh2->fatal_rv)
178
0
    return ngh2->fatal_rv;
179
0
  return ngh2_check(ngh2, nghttp2_submit_rst_stream(
180
0
    ngh2->s, flags, stream_id, error_code));
181
0
}
182
183
int Curl_ngh2_session_send(struct curl_ngh2 *ngh2)
184
0
{
185
0
  int rv;
186
0
  if(ngh2->fatal_rv)
187
0
    return ngh2->fatal_rv;
188
0
  rv = ngh2_check(ngh2, nghttp2_session_send(ngh2->s));
189
  /* a callback might trigger a fatal state without session_send()
190
   * noticing. Check again. */
191
0
  return ngh2->fatal_rv ? ngh2->fatal_rv : rv;
192
0
}
193
194
int Curl_ngh2_session_client_new3(
195
  struct curl_ngh2 *ngh2, const nghttp2_session_callbacks *callbacks,
196
  void *user_data, const nghttp2_option *option, nghttp2_mem *mem)
197
0
{
198
0
  if(ngh2->s)
199
0
    ngh2->fatal_rv = NGHTTP2_ERR_FATAL;
200
0
  if(ngh2->fatal_rv)
201
0
    return ngh2->fatal_rv;
202
0
  return ngh2_check(ngh2,
203
0
    nghttp2_session_client_new3(
204
0
      &(ngh2->s), callbacks, user_data, option, mem));
205
0
}
206
207
int Curl_ngh2_session_want_read(struct curl_ngh2 *ngh2)
208
0
{
209
0
  if(!Curl_ngh2_valid(ngh2))
210
0
    return 0;
211
0
  return nghttp2_session_want_read(ngh2->s);
212
0
}
213
214
int Curl_ngh2_session_want_write(struct curl_ngh2 *ngh2)
215
0
{
216
0
  if(!Curl_ngh2_valid(ngh2))
217
0
    return 0;
218
0
  return nghttp2_session_want_write(ngh2->s);
219
0
}
220
221
ssize_t Curl_ngh2_session_mem_recv(
222
  struct curl_ngh2 *ngh2, const uint8_t *in, size_t inlen)
223
0
{
224
0
  ssize_t rv;
225
0
  if(ngh2->fatal_rv)
226
0
    return ngh2->fatal_rv;
227
0
  rv = ngh2_checks(ngh2, nghttp2_session_mem_recv(ngh2->s, in, inlen));
228
  /* the session might encounter a fatal state in a callback,
229
   * but session_mem_rec() might not notice and return a non-error.
230
   * Check again. */
231
0
  return ngh2->fatal_rv ? ngh2->fatal_rv : rv;
232
0
}
233
234
int Curl_ngh2_session_check_request_allowed(struct curl_ngh2 *ngh2)
235
0
{
236
0
  if(!Curl_ngh2_valid(ngh2))
237
0
    return 0;
238
0
  return nghttp2_session_check_request_allowed(ngh2->s);
239
0
}
240
241
int Curl_ngh2_submit_ping(
242
  struct curl_ngh2 *ngh2, uint8_t flags, const uint8_t *opaque_data)
243
0
{
244
0
  if(ngh2->fatal_rv)
245
0
    return ngh2->fatal_rv;
246
0
  return ngh2_check(ngh2,
247
0
    nghttp2_submit_ping(ngh2->s, flags, opaque_data));
248
0
}
249
250
int32_t Curl_ngh2_session_get_stream_effective_recv_data_length(
251
  struct curl_ngh2 *ngh2, int32_t stream_id)
252
0
{
253
0
  if(!Curl_ngh2_valid(ngh2))
254
0
    return 0;
255
0
  return nghttp2_session_get_stream_effective_recv_data_length(
256
0
    ngh2->s, stream_id);
257
0
}
258
259
int Curl_ngh2_session_resume_data(
260
  struct curl_ngh2 *ngh2, int32_t stream_id)
261
0
{
262
0
  if(ngh2->fatal_rv)
263
0
    return ngh2->fatal_rv;
264
0
  return ngh2_check(ngh2,
265
0
    nghttp2_session_resume_data(ngh2->s, stream_id));
266
0
}
267
268
int Curl_ngh2_session_consume(
269
  struct curl_ngh2 *ngh2, int32_t stream_id, size_t size)
270
0
{
271
0
  if(ngh2->fatal_rv)
272
0
    return ngh2->fatal_rv;
273
0
  return ngh2_check(ngh2,
274
0
    nghttp2_session_consume(ngh2->s, stream_id, size));
275
0
}
276
277
int Curl_ngh2_submit_priority(
278
  struct curl_ngh2 *ngh2, uint8_t flags,
279
  int32_t stream_id, const nghttp2_priority_spec *pri_spec)
280
0
{
281
0
  if(ngh2->fatal_rv)
282
0
    return ngh2->fatal_rv;
283
0
  return ngh2_check(ngh2,
284
0
    nghttp2_submit_priority(ngh2->s, flags, stream_id, pri_spec));
285
0
}
286
287
int32_t Curl_ngh2_submit_request(
288
  struct curl_ngh2 *ngh2, const nghttp2_priority_spec *pri_spec,
289
  const nghttp2_nv *nva, size_t nvlen, const nghttp2_data_provider *data_prd,
290
  void *stream_user_data)
291
0
{
292
0
  if(ngh2->fatal_rv)
293
0
    return (int32_t)ngh2->fatal_rv;
294
0
  return ngh2_check32(ngh2,
295
0
    nghttp2_submit_request(ngh2->s, pri_spec, nva, nvlen,
296
0
      data_prd, stream_user_data));
297
0
}
298
299
int Curl_ngh2_session_upgrade2(
300
  struct curl_ngh2 *ngh2, const uint8_t *settings_payload,
301
  size_t settings_payloadlen, int head_request, void *stream_user_data)
302
0
{
303
0
  if(ngh2->fatal_rv)
304
0
    return ngh2->fatal_rv;
305
0
  return ngh2_check(ngh2,
306
0
    nghttp2_session_upgrade2(ngh2->s, settings_payload,
307
0
      settings_payloadlen, head_request, stream_user_data));
308
0
}
309
310
int Curl_ngh2_submit_goaway(
311
  struct curl_ngh2 *ngh2, uint8_t flags, int32_t last_stream_id,
312
  uint32_t error_code, const uint8_t *opaque_data, size_t opaque_data_len)
313
0
{
314
0
  if(ngh2->fatal_rv)
315
0
    return ngh2->fatal_rv;
316
0
  return ngh2_check(ngh2,
317
0
    nghttp2_submit_goaway(ngh2->s, flags, last_stream_id, error_code,
318
0
    opaque_data, opaque_data_len));
319
0
}
320
321
#endif /* !CURL_DISABLE_HTTP && USE_NGHTTP2 */