/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 */ |