1use crate::Header;
29use crate::StreamId;
30use std::collections::hash_map;
31use std::collections::HashMap;
32use std::fmt::Debug;
33use std::fmt::Display;
34use std::marker::PhantomPinned;
35use std::pin::Pin;
36
37pub struct DecoderError;
39
40pub enum DecoderOutput {
46 Done(Vec<Header>),
48
49 BlockedStream,
53}
54
55impl DecoderOutput {
56 pub fn take(self) -> Option<Vec<Header>> {
59 match self {
60 Self::Done(v) => Some(v),
61 Self::BlockedStream => None,
62 }
63 }
64
65 pub fn is_blocked(&self) -> bool {
67 matches!(self, Self::BlockedStream)
68 }
69}
70
71pub struct Decoder {
73 inner: Pin<Box<InnerDecoder>>,
74}
75
76impl Decoder {
77 pub fn new(dyn_table_size: u32, max_blocked_streams: u32) -> Self {
82 Self {
83 inner: InnerDecoder::new(dyn_table_size, max_blocked_streams),
84 }
85 }
86
87 pub fn decode<D>(&mut self, stream_id: StreamId, data: D) -> Result<DecoderOutput, DecoderError>
108 where
109 D: AsRef<[u8]>,
110 {
111 self.inner
112 .as_mut()
113 .feed_header_data(stream_id, data.as_ref())
114 }
115
116 pub fn feed<D>(&mut self, data: D) -> Result<(), DecoderError>
118 where
119 D: AsRef<[u8]>,
120 {
121 self.inner.as_mut().feed_encoder_data(data.as_ref())
122 }
123
124 pub fn unblocked(
130 &mut self,
131 stream_id: StreamId,
132 ) -> Option<Result<DecoderOutput, DecoderError>> {
133 self.inner.as_mut().process_decoded_data(stream_id)
134 }
135}
136
137struct InnerDecoder {
138 decoder: ls_qpack_sys::lsqpack_dec,
139 header_blocks: HashMap<StreamId, Pin<Box<callbacks::HeaderBlockCtx>>>,
140 _marker: PhantomPinned,
141}
142
143impl InnerDecoder {
144 fn new(dyn_table_size: u32, max_blocked_streams: u32) -> Pin<Box<Self>> {
145 let mut this = Box::new(Self {
146 decoder: ls_qpack_sys::lsqpack_dec::default(),
147 header_blocks: HashMap::new(),
148 _marker: PhantomPinned,
149 });
150
151 unsafe {
152 ls_qpack_sys::lsqpack_dec_init(
153 &mut this.decoder,
154 std::ptr::null_mut(),
155 dyn_table_size,
156 max_blocked_streams,
157 &callbacks::HSET_IF_CALLBACKS,
158 0,
159 );
160 }
161
162 Box::into_pin(this)
163 }
164
165 fn feed_header_data(
166 self: Pin<&mut Self>,
167 stream_id: StreamId,
168 data: &[u8],
169 ) -> Result<DecoderOutput, DecoderError> {
170 let this = unsafe { self.get_unchecked_mut() };
171
172 if this.header_blocks.contains_key(&stream_id) {
173 todo!()
174 }
175
176 let mut hblock_ctx =
177 callbacks::HeaderBlockCtx::new(&mut this.decoder, data.to_vec().into_boxed_slice());
178
179 let encoded_cursor = hblock_ctx.as_ref().encoded_cursor();
180 let encoded_cursor_len = encoded_cursor.len();
181 let header_block_len = encoded_cursor.len();
182 let mut cursor_after = encoded_cursor.as_ptr();
183
184 let result = unsafe {
185 ls_qpack_sys::lsqpack_dec_header_in(
186 &mut this.decoder,
187 hblock_ctx.as_mut().as_mut_ptr() as *mut libc::c_void,
188 stream_id.value(),
189 header_block_len,
190 &mut cursor_after,
191 encoded_cursor_len,
192 std::ptr::null_mut(),
193 &mut 0,
194 )
195 };
196
197 match result {
198 ls_qpack_sys::lsqpack_read_header_status_LQRHS_DONE => {
199 debug_assert!(!hblock_ctx.as_ref().is_blocked());
200 debug_assert!(!hblock_ctx.as_ref().is_error());
201
202 let hblock_ctx = unsafe { Pin::into_inner_unchecked(hblock_ctx) };
203 Ok(DecoderOutput::Done(hblock_ctx.decoded_headers()))
204 }
205
206 ls_qpack_sys::lsqpack_read_header_status_LQRHS_BLOCKED => {
207 let offset = unsafe {
208 cursor_after.offset_from(hblock_ctx.as_ref().encoded_cursor().as_ptr())
209 };
210
211 debug_assert!(offset > 0);
212
213 hblock_ctx.as_mut().advance_cursor(offset as usize);
214 hblock_ctx.as_mut().set_blocked(true);
215 this.header_blocks.insert(stream_id, hblock_ctx);
216
217 Ok(DecoderOutput::BlockedStream)
218 }
219
220 ls_qpack_sys::lsqpack_read_header_status_LQRHS_NEED => unimplemented!(),
221
222 _ => Err(DecoderError),
223 }
224 }
225
226 fn feed_encoder_data(self: Pin<&mut Self>, data: &[u8]) -> Result<(), DecoderError> {
227 let this = unsafe { self.get_unchecked_mut() };
228
229 let result = unsafe {
230 ls_qpack_sys::lsqpack_dec_enc_in(&mut this.decoder, data.as_ptr(), data.len())
231 };
232
233 if result == 0 {
234 Ok(())
235 } else {
236 Err(DecoderError)
237 }
238 }
239
240 fn process_decoded_data(
241 self: Pin<&mut Self>,
242 stream_id: StreamId,
243 ) -> Option<Result<DecoderOutput, DecoderError>> {
244 let this = unsafe { self.get_unchecked_mut() };
245
246 match this.header_blocks.entry(stream_id) {
247 hash_map::Entry::Occupied(hdbk) => {
248 if hdbk.get().as_ref().is_blocked() {
249 debug_assert!(!hdbk.get().as_ref().is_error());
250 return Some(Ok(DecoderOutput::BlockedStream));
251 }
252
253 let hdbk = hdbk.remove();
254
255 if hdbk.as_ref().is_error() {
256 debug_assert!(!hdbk.as_ref().is_blocked());
257 return Some(Err(DecoderError));
258 }
259
260 let hdbk = unsafe { Pin::into_inner_unchecked(hdbk) };
261 Some(Ok(DecoderOutput::Done(hdbk.decoded_headers())))
262 }
263
264 hash_map::Entry::Vacant(_) => None,
265 }
266 }
267}
268
269impl Drop for InnerDecoder {
270 fn drop(&mut self) {
271 unsafe { ls_qpack_sys::lsqpack_dec_cleanup(&mut self.decoder) }
272 }
273}
274
275mod callbacks {
276 use crate::header::HeaderError;
277 use crate::Header;
278 use std::ffi::c_char;
279 use std::marker::PhantomPinned;
280 use std::pin::Pin;
281
282 pub(super) static HSET_IF_CALLBACKS: ls_qpack_sys::lsqpack_dec_hset_if =
283 ls_qpack_sys::lsqpack_dec_hset_if {
284 dhi_unblocked: Some(dhi_unblocked),
285 dhi_prepare_decode: Some(dhi_prepare_decode),
286 dhi_process_header: Some(dhi_process_header),
287 };
288
289 #[derive(Debug)]
290 pub(super) struct HeaderBlockCtx {
291 decoder: *mut ls_qpack_sys::lsqpack_dec, encoded_data: Box<[u8]>,
293 encoded_data_offset: usize,
294 decoding_buffer: Vec<u8>,
295 header: ls_qpack_sys::lsxpack_header,
296 blocked: bool,
297 error: bool,
298 decoded_headers: Vec<Header>,
299 _marker: PhantomPinned,
300 }
301
302 impl HeaderBlockCtx {
303 pub(super) fn new(
304 decoder: *mut ls_qpack_sys::lsqpack_dec,
305 encoded_data: Box<[u8]>,
306 ) -> Pin<Box<Self>> {
307 debug_assert!(!decoder.is_null());
308
309 Box::pin(Self {
310 decoder,
311 encoded_data,
312 encoded_data_offset: 0,
313 decoding_buffer: Vec::new(),
314 header: Default::default(),
315 blocked: false,
316 error: false,
317 decoded_headers: Default::default(),
318 _marker: PhantomPinned,
319 })
320 }
321
322 pub(super) unsafe fn as_mut_ptr(mut self: Pin<&mut Self>) -> *mut HeaderBlockCtx {
323 self.as_mut().get_unchecked_mut()
324 }
325
326 pub(super) fn encoded_cursor<'a>(self: Pin<&'a Self>) -> &'a [u8] {
327 debug_assert!(self.encoded_data_offset < self.encoded_data.len());
328 &self.get_ref().encoded_data[self.encoded_data_offset..]
329 }
330
331 pub(super) fn advance_cursor(self: Pin<&mut Self>, offset: usize) {
332 debug_assert!(offset <= self.encoded_data.len());
333 let this = unsafe { self.get_unchecked_mut() };
334 this.encoded_data_offset += offset;
335 }
336
337 pub(super) fn set_blocked(self: Pin<&mut Self>, blocked: bool) {
338 let this = unsafe { self.get_unchecked_mut() };
339 this.blocked = blocked;
340 }
341
342 pub(super) fn enable_error(self: Pin<&mut Self>) {
343 let this = unsafe { self.get_unchecked_mut() };
344 debug_assert!(!this.error);
345 this.error = true;
346 }
347
348 pub(super) fn is_blocked(self: Pin<&Self>) -> bool {
349 self.blocked
350 }
351
352 pub(super) fn is_error(self: Pin<&Self>) -> bool {
353 self.error
354 }
355
356 pub(super) fn decoded_headers(self) -> Vec<Header> {
357 self.decoded_headers
358 }
359
360 unsafe fn from_void_ptr(ptr: *mut libc::c_void) -> Pin<&'static mut Self> {
361 debug_assert!(!ptr.is_null());
362 Pin::new_unchecked(&mut *(ptr as *mut _))
363 }
364
365 fn reset_header(self: Pin<&mut Self>) {
366 let this = unsafe { self.get_unchecked_mut() };
367 this.header = Default::default()
368 }
369
370 fn resize_header(self: Pin<&mut Self>, space: u16) {
371 let this = unsafe { self.get_unchecked_mut() };
372 this.decoding_buffer
373 .resize(space as usize, Default::default());
374
375 this.header.buf = this.decoding_buffer.as_mut_ptr() as *mut c_char;
376 this.header.val_len = space;
377 }
378
379 fn header_mut(self: Pin<&mut Self>) -> &mut ls_qpack_sys::lsxpack_header {
380 let this = unsafe { self.get_unchecked_mut() };
381 &mut this.header
382 }
383
384 fn process_header(self: Pin<&mut Self>) -> Result<(), HeaderError> {
385 let this = unsafe { self.get_unchecked_mut() };
386
387 let header = Header::with_buffer(
388 std::mem::take(&mut this.decoding_buffer).into_boxed_slice(),
389 this.header.name_offset as usize,
390 this.header.name_len as usize,
391 this.header.val_offset as usize,
392 this.header.val_len as usize,
393 )?;
394
395 this.decoded_headers.push(header);
396
397 this.header = Default::default();
398
399 Ok(())
400 }
401 }
402
403 extern "C" fn dhi_unblocked(hblock_ctx: *mut libc::c_void) {
404 let mut hblock_ctx = unsafe { HeaderBlockCtx::from_void_ptr(hblock_ctx) };
405
406 debug_assert!(hblock_ctx.as_ref().is_blocked());
407 hblock_ctx.as_mut().set_blocked(false);
408
409 let encoded_cursor = hblock_ctx.as_ref().encoded_cursor();
410 let encoded_cursor_len = encoded_cursor.len();
411 let mut cursor_after = encoded_cursor.as_ptr();
412
413 let result = unsafe {
414 ls_qpack_sys::lsqpack_dec_header_read(
415 hblock_ctx.decoder,
416 hblock_ctx.as_mut().as_mut_ptr() as *mut libc::c_void,
417 &mut cursor_after,
418 encoded_cursor_len,
419 std::ptr::null_mut(),
420 std::ptr::null_mut(),
421 )
422 };
423
424 match result {
425 ls_qpack_sys::lsqpack_read_header_status_LQRHS_DONE => {}
426
427 ls_qpack_sys::lsqpack_read_header_status_LQRHS_BLOCKED => {
428 let offset = unsafe {
429 cursor_after.offset_from(hblock_ctx.as_ref().encoded_cursor().as_ptr())
430 };
431
432 debug_assert!(offset > 0);
433
434 hblock_ctx.as_mut().advance_cursor(offset as usize);
435 hblock_ctx.as_mut().set_blocked(true);
436 }
437
438 ls_qpack_sys::lsqpack_read_header_status_LQRHS_NEED => unimplemented!(),
439
440 _ => {
441 hblock_ctx.as_mut().enable_error();
442 }
443 }
444 }
445
446 extern "C" fn dhi_prepare_decode(
447 hblock_ctx: *mut libc::c_void,
448 header: *mut ls_qpack_sys::lsxpack_header,
449 space: libc::size_t,
450 ) -> *mut ls_qpack_sys::lsxpack_header {
451 const MAX_SPACE: usize = u16::MAX as usize;
452
453 let mut hblock_ctx = unsafe { HeaderBlockCtx::from_void_ptr(hblock_ctx) };
454
455 if space > MAX_SPACE {
456 todo!()
457 }
458
459 let space = space as u16;
460
461 if header.is_null() {
462 hblock_ctx.as_mut().reset_header();
463 } else {
464 assert!(std::ptr::eq(&hblock_ctx.header, header));
465 assert!(space > hblock_ctx.header.val_len);
466 }
467
468 hblock_ctx.as_mut().resize_header(space);
469 hblock_ctx.as_mut().header_mut()
470 }
471
472 extern "C" fn dhi_process_header(
473 hblock_ctx: *mut libc::c_void,
474 header: *mut ls_qpack_sys::lsxpack_header,
475 ) -> libc::c_int {
476 let hblock_ctx = unsafe { HeaderBlockCtx::from_void_ptr(hblock_ctx) };
477
478 debug_assert!(!hblock_ctx.blocked);
479 debug_assert_eq!(header as *const _, &hblock_ctx.header);
480
481 match hblock_ctx.process_header() {
482 Ok(()) => 0,
483 Err(_) => todo!(),
484 }
485 }
486}
487
488impl Debug for DecoderError {
489 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
490 f.debug_struct("DecoderError").finish()
491 }
492}
493
494impl Display for DecoderError {
495 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
496 Debug::fmt(self, f)
497 }
498}
499
500impl std::error::Error for DecoderError {}