Skip to main content

sark_http/h1/head/request/
plan.rs

1use std::{convert::Infallible, num::NonZero};
2
3use line::error;
4
5use crate::{
6    h1::{
7        field,
8        field::Connection,
9        framing,
10        head::{
11            Boundary, Limit, ParseError, Semantic, line,
12            request::{Fields, route},
13            state,
14            tail::Tail,
15        },
16        switch, target,
17    },
18    payload::response::Method,
19    request,
20    request::span,
21};
22
23#[derive(Clone, Copy)]
24pub struct Plan {
25    admission: framing::Admission,
26    pub(super) route: route::Line,
27    connection: Connection,
28    upgrades: switch::Offers,
29    version: line::Version,
30    tail: Tail,
31}
32
33#[derive(Clone, Copy)]
34pub(in crate::h1::head::request) struct Start {
35    target: span::Span,
36    plan: target::Target,
37    method: u32,
38    version: line::Version,
39    transition: Method,
40    fields: u32,
41}
42
43#[derive(Clone, Copy)]
44pub(in crate::h1::head::request) enum Kind {}
45
46impl Start {
47    pub(super) fn try_new(
48        line: line::Request<'_>,
49        limit: Limit,
50    ) -> Result<Self, ParseError<Infallible>> {
51        if line.end() > limit.bytes() {
52            return Err(ParseError::too_large(line.end(), limit.bytes()));
53        }
54        Self::from(line).map_err(ParseError::Boundary)
55    }
56
57    pub(super) fn from(line: line::Request<'_>) -> Result<Self, Boundary> {
58        let fields = line.end();
59        let fields = u32::try_from(fields).map_err(|_| Boundary::TooLarge {
60            actual: fields,
61            limit: u32::MAX as usize,
62        })?;
63        Ok(Self {
64            target: line.target_span(),
65            plan: line.plan(),
66            method: line.method().len() as u32,
67            version: line.version(),
68            transition: Method::from_bytes(line.method()),
69            fields,
70        })
71    }
72}
73
74impl Plan {
75    pub const fn admission(&self) -> framing::Admission {
76        self.admission
77    }
78
79    pub const fn request(&self) -> request::Layout {
80        self.route.layout()
81    }
82
83    pub const fn connection(&self) -> Connection {
84        self.connection
85    }
86
87    pub const fn transition(&self) -> switch::Intent {
88        self.route.transition()
89    }
90
91    pub const fn upgrades(&self) -> switch::Offers {
92        self.upgrades
93    }
94
95    pub const fn version(&self) -> line::Version {
96        self.version
97    }
98
99    pub const fn fields(&self) -> span::Span {
100        self.tail.fields()
101    }
102
103    pub const fn wire_len(&self) -> NonZero<u32> {
104        self.tail.wire_len()
105    }
106}
107
108impl state::Kind for Kind {
109    type Start = Start;
110    type Fields = Fields;
111    type Parts = Plan;
112
113    fn start<E>(bytes: &[u8]) -> Result<line::Progress<Start>, ParseError<E>> {
114        let progress = match line::Request::progress(bytes) {
115            Ok(progress) => progress,
116            Err(error::Request::Syntax) => return Err(ParseError::invalid()),
117            Err(error::Request::Target(cause)) => {
118                return Err(ParseError::Semantic(Semantic::Authority(cause)));
119            }
120            Err(error::Request::Span(cause)) => {
121                return Err(ParseError::Boundary(Boundary::Span(cause)));
122            }
123        };
124        match progress {
125            line::Progress::Complete(line) => match Start::from(line) {
126                Ok(start) => Ok(line::Progress::Complete(start)),
127                Err(cause) => Err(ParseError::Boundary(cause)),
128            },
129            line::Progress::Partial(cursor) => Ok(line::Progress::Partial(cursor)),
130        }
131    }
132
133    fn fields(start: Start) -> u32 {
134        start.fields
135    }
136
137    fn observe(
138        start: &Start,
139        fields: Fields,
140        field: &field::Entry<'_>,
141    ) -> Result<Fields, Semantic> {
142        fields.apply(field, start.version)
143    }
144
145    fn finish<E>(fields: Fields, start: Start, tail: Tail) -> Result<Plan, ParseError<E>> {
146        let conn = fields.connection();
147        let upgrades = fields.upgrades();
148        let intent = fields
149            .transition(start.transition, start.version)
150            .map_err(ParseError::Semantic)?;
151        let (permit, request, auth) = fields
152            .admit_parts(start.plan, start.target, start.version)
153            .map_err(ParseError::Semantic)?;
154        Ok(Plan {
155            admission: permit,
156            route: route::Line::new(request, start.method, auth, intent, permit.expectation()),
157            connection: conn,
158            upgrades,
159            version: start.version,
160            tail,
161        })
162    }
163}