1#![allow(unused_imports)]
2
3extern crate alloc;
4
5use alloc::ffi::CString;
6use alloc::vec::Vec;
7use alloc::{boxed::Box, format};
8use core::cell::{Cell, RefCell};
9use core::ffi::{c_char, c_uchar, c_void};
10use core::fmt::Debug;
11use core::ptr;
12use core::str;
13use core::{slice, slice::from_raw_parts};
14
15use milo_macros::{callback, generate, next};
16
17#[repr(C)]
18#[derive(Clone, Debug)]
19pub struct Parser {
20 pub autodetect: bool,
22 pub is_request: bool,
23 pub manage_unconsumed: bool,
24 pub continue_without_data: bool,
25 pub is_connect: bool,
26 pub skip_body: bool,
27 pub max_start_line_length: usize,
28 pub max_header_length: usize,
29 #[cfg(not(target_family = "wasm"))]
30 pub context: *mut c_void,
31 #[cfg(any(debug_assertions, feature = "debug"))]
32 pub debug: bool,
33
34 pub state: u8,
36 pub position: usize,
37 pub parsed: u64,
38 pub paused: bool,
39 pub error_code: u8,
40
41 pub method: u8,
43 pub status: u32,
44 pub version_major: u8,
45 pub version_minor: u8,
46 pub content_length: u64,
47 pub chunk_size: u64,
48 pub remaining_content_length: u64,
49 pub remaining_chunk_size: u64,
50 pub has_content_length: bool,
51 pub has_transfer_encoding: bool,
52 pub has_chunked_transfer_encoding: bool,
53 pub has_connection_close: bool,
54 pub has_connection_upgrade: bool,
55 pub has_upgrade: bool,
56 pub has_trailers: bool,
57
58 pub active_callbacks: u64,
60 #[cfg(not(target_family = "wasm"))]
61 pub callbacks: ParserCallbacks,
62
63 #[cfg(target_family = "wasm")]
65 pub ptr: *mut c_void,
66
67 pub error_description: *const c_uchar,
69 pub error_description_len: u16,
70 pub unconsumed: *const c_uchar,
71 pub unconsumed_len: usize,
72}
73
74#[cfg(not(target_family = "wasm"))]
75mod native;
76
77#[cfg(not(target_family = "wasm"))]
78pub use crate::native::*;
79
80#[cfg(target_family = "wasm")]
81mod wasm;
82
83#[cfg(target_family = "wasm")]
84pub use crate::wasm::*;
85
86generate!();
87
88impl Parser {
89 pub fn new() -> Parser {
91 Parser {
92 autodetect: true,
94 is_request: false,
95 manage_unconsumed: false,
96 continue_without_data: false,
97 is_connect: false,
98 skip_body: false,
99 max_start_line_length: 8192,
100 max_header_length: 8192,
101 #[cfg(any(debug_assertions, feature = "debug"))]
102 debug: false,
103 #[cfg(not(target_family = "wasm"))]
104 context: ptr::null_mut(),
105 state: STATE_START,
107 position: 0,
108 parsed: 0,
109 paused: false,
110 error_code: ERROR_NONE,
111 method: 0,
113 status: 0,
114 version_major: 0,
115 version_minor: 0,
116 content_length: 0,
117 chunk_size: 0,
118 remaining_content_length: 0,
119 remaining_chunk_size: 0,
120 has_content_length: false,
121 has_transfer_encoding: false,
122 has_chunked_transfer_encoding: false,
123 has_connection_close: false,
124 has_connection_upgrade: false,
125 has_upgrade: false,
126 has_trailers: false,
127 active_callbacks: 0,
129 #[cfg(not(target_family = "wasm"))]
130 callbacks: ParserCallbacks::new(),
131 #[cfg(target_family = "wasm")]
133 ptr: ptr::null_mut(),
134 error_description: ptr::null(),
136 error_description_len: 0,
137 unconsumed: ptr::null(),
138 unconsumed_len: 0,
139 }
140 }
141
142 pub fn reset(&mut self, keep_parsed: bool) {
154 self.state = STATE_START;
155 self.paused = false;
156
157 if !keep_parsed {
158 self.parsed = 0;
159 }
160
161 self.error_code = ERROR_NONE;
162
163 if self.error_description_len > 0 {
164 unsafe {
165 let _ = slice::from_raw_parts(self.error_description, self.error_description_len as usize);
166 }
167
168 self.error_description = ptr::null();
169 self.error_description_len = 0;
170 }
171
172 if self.unconsumed_len > 0 {
173 unsafe {
174 let _ = slice::from_raw_parts(self.unconsumed, self.unconsumed_len);
175 }
176
177 self.unconsumed = ptr::null();
178 self.unconsumed_len = 0;
179 }
180
181 self.clear();
182 callback!(on_reset);
183 }
184
185 pub fn clear(&mut self) {
187 self.is_connect = false;
188 self.method = 0;
189 self.status = 0;
190 self.version_major = 0;
191 self.version_minor = 0;
192 self.has_content_length = false;
193 self.has_transfer_encoding = false;
194 self.has_chunked_transfer_encoding = false;
195 self.has_connection_close = false;
196 self.has_connection_upgrade = false;
197 self.has_upgrade = false;
198 self.has_trailers = false;
199 self.content_length = 0;
200 self.chunk_size = 0;
201 self.remaining_content_length = 0;
202 self.remaining_chunk_size = 0;
203 self.skip_body = false;
204 }
205
206 pub fn pause(&mut self) { self.paused = true; }
208
209 pub fn resume(&mut self) { self.paused = false; }
211
212 pub fn finish(&mut self) {
215 match self.state {
216 STATE_START | STATE_REQUEST_LINE | STATE_STATUS_LINE | STATE_FINISH => {
218 self.state = STATE_FINISH;
219 }
220 STATE_BODY_WITH_NO_LENGTH => {
221 callback!(on_message_complete);
223
224 self.state = STATE_FINISH;
226 }
227 STATE_ERROR => (),
228 _ => {
230 self.fail(ERROR_UNEXPECTED_EOF, "Unexpected end of data");
231 }
232 }
233 }
234
235 #[inline(always)]
239 pub fn fail(&mut self, code: u8, description: &str) {
240 let description_copy = description.to_string();
241 let (ptr, _, len) = description_copy.into_raw_parts();
242
243 self.state = STATE_ERROR;
244 self.error_code = code;
245 self.error_description = ptr;
246 self.error_description_len = len as u16;
247 callback!(on_error, 0, 0);
248 }
249
250 pub fn state_str(&self) -> &str { States::try_from(self.state).unwrap().as_str() }
252
253 pub fn error_code_str(&self) -> &str { Errors::try_from(self.error_code).unwrap().as_str() }
255
256 pub fn error_description_str(&self) -> &str {
258 unsafe {
259 if self.error_description_len > 0 {
260 str::from_utf8_unchecked(from_raw_parts(
261 self.error_description,
262 self.error_description_len as usize,
263 ))
264 } else {
265 ""
266 }
267 }
268 }
269}
270
271impl Default for Parser {
272 fn default() -> Self { Self::new() }
273}
274
275mod matchers;
276mod parse;