webparse/http/http2/frame/
priority.rs

1// Copyright 2022 - 2023 Wenmeng See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8//
9// Author: tickbh
10// -----
11// Created Date: 2023/09/01 04:35:19
12
13use crate::{Http2Error, WebResult};
14use algorithm::buf::{Bt, BtMut};
15
16use super::{frame::Frame, Flag, FrameHeader, StreamIdentifier, MASK_U31};
17
18#[derive(Debug, Eq, PartialEq, Clone)]
19pub struct Priority {
20    stream_id: StreamIdentifier,
21    dependency: StreamDependency,
22}
23
24#[derive(Debug, Eq, PartialEq, Clone)]
25pub struct StreamDependency {
26    /// The ID of the stream dependency target
27    dependency_id: StreamIdentifier,
28
29    /// The weight for the stream. The value exposed (and set) here is always in
30    /// the range [0, 255], instead of [1, 256] (as defined in section 5.3.2.)
31    /// so that the value fits into a `u8`.
32    weight: u8,
33
34    /// True if the stream dependency is exclusive.
35    is_exclusive: bool,
36}
37
38impl Priority {
39    pub fn parse<B: Bt>(head: FrameHeader, payload: &mut B) -> WebResult<Self> {
40        let dependency = StreamDependency::load(payload)?;
41
42        if dependency.dependency_id() == head.stream_id() {
43            return Err(Http2Error::InvalidDependencyId.into());
44        }
45
46        Ok(Priority {
47            stream_id: head.stream_id(),
48            dependency,
49        })
50    }
51
52    pub fn into(self) -> (StreamIdentifier, StreamIdentifier, u8) {
53        (
54            self.stream_id,
55            self.dependency.dependency_id,
56            self.dependency.weight,
57        )
58    }
59
60    pub fn stream_id(&self) -> StreamIdentifier {
61        self.stream_id
62    }
63
64    pub fn dependency_id(&self) -> StreamIdentifier {
65        self.dependency.dependency_id
66    }
67
68    pub fn weight(&self) -> u8 {
69        self.dependency.weight
70    }
71
72    pub fn encode<B: Bt + BtMut>(&self, dst: &mut B) -> WebResult<usize> {
73        let head = FrameHeader::new(super::Kind::Priority, Flag::zero(), self.stream_id);
74        let mut size = 0;
75        size += head.encode(dst)?;
76        size += self.dependency.encode(dst)?;
77        log::trace!("HTTP2: 编码优先级信息; len={}", size);
78        Ok(size)
79    }
80}
81
82impl<B> From<Priority> for Frame<B> {
83    fn from(src: Priority) -> Self {
84        Frame::Priority(src)
85    }
86}
87
88// ===== impl StreamDependency =====
89
90impl StreamDependency {
91    pub fn new(dependency_id: StreamIdentifier, weight: u8, is_exclusive: bool) -> Self {
92        StreamDependency {
93            dependency_id,
94            weight,
95            is_exclusive,
96        }
97    }
98
99    pub fn load<B: Bt>(src: &mut B) -> WebResult<Self> {
100        if src.remaining() < 5 {
101            return Err(Http2Error::InvalidPayloadLength.into());
102        }
103
104        let value = src.get_u32();
105        let id = value & MASK_U31;
106        let is_exclusive = value - id != 0;
107
108        let dependency_id = StreamIdentifier(id);
109        let weight = src.get_u8();
110        Ok(StreamDependency::new(dependency_id, weight, is_exclusive))
111    }
112
113    pub fn dependency_id(&self) -> StreamIdentifier {
114        self.dependency_id
115    }
116
117    fn encode<B: Bt + BtMut>(&self, dst: &mut B) -> WebResult<usize> {
118        self.dependency_id.encode(dst)?;
119        dst.put_u8(self.weight);
120        Ok(5)
121    }
122}