sark_http/h1/head/request/
plan.rs1use 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}