h3i/prompts/h3/
settings.rs1use inquire::error::InquireResult;
28use inquire::validator::Validation;
29use inquire::Text;
30
31use super::squish_suggester;
32use super::stream::prompt_fin_stream;
33use super::SuggestionResult;
34use crate::actions::h3::Action;
35use crate::prompts::h3;
36
37use crate::quiche;
38
39const QPACK_MAX_TABLE_CAPACITY: &str = "QPACK_MAX_TABLE_CAPACITY";
40const MAX_FIELD_SECTION_SIZE: &str = "MAX_FIELD_SECTION_SIZE";
41const QPACK_BLOCKED_STREAMS: &str = "QPACK_BLOCKED_STREAMS";
42const ENABLE_CONNECT_PROTOCOL: &str = "ENABLE_CONNECT_PROTOCOL";
43const H3_DATAGRAM: &str = "H3_DATAGRAM";
44
45type RawSettings = Vec<(u64, u64)>;
46
47pub fn prompt_settings() -> InquireResult<Action> {
48 let stream_id = h3::prompt_control_stream_id()?;
49 let settings = settings_read_loop();
50
51 let fin_stream = prompt_fin_stream()?;
52
53 let action = Action::SendFrame {
54 stream_id,
55 fin_stream,
56 frame: quiche::h3::frame::Frame::Settings {
57 max_field_section_size: None,
58 qpack_max_table_capacity: None,
59 qpack_blocked_streams: None,
60 connect_protocol_enabled: None,
61 h3_datagram: None,
62 grease: None,
63 raw: None,
64 additional_settings: Some(settings),
65 },
66 expected_result: Default::default(),
67 };
68
69 Ok(action)
70}
71
72fn settings_read_loop() -> RawSettings {
73 let mut settings = vec![];
74
75 loop {
76 let ty = match Text::new("setting type:")
77 .with_validator(validate_setting_type)
78 .with_autocomplete(&settings_type_suggestor)
79 .with_help_message("type 'q!' to stop adding settings")
80 .prompt()
81 {
82 Ok(h) => {
83 if h == "q!" {
84 break;
85 }
86
87 h
88 },
89 Err(_) => {
90 println!("An error happened, stopping.");
91 break;
92 },
93 };
94
95 let ty = match ty.as_str() {
96 QPACK_MAX_TABLE_CAPACITY => 0x1,
97 MAX_FIELD_SECTION_SIZE => 0x6,
98 QPACK_BLOCKED_STREAMS => 0x7,
99 ENABLE_CONNECT_PROTOCOL => 0x8,
100 H3_DATAGRAM => 0x33,
101
102 v => v.parse::<u64>().unwrap(),
103 };
104
105 let value = Text::new("setting value:")
106 .with_validator(h3::validate_varint)
107 .prompt()
108 .expect("An error happened, stopping.")
109 .parse::<u64>()
110 .unwrap();
111
112 settings.push((ty, value));
113 }
114
115 settings
116}
117
118fn validate_setting_type(id: &str) -> SuggestionResult<Validation> {
119 if matches!(
120 id,
121 "q!" | QPACK_MAX_TABLE_CAPACITY |
122 MAX_FIELD_SECTION_SIZE |
123 QPACK_BLOCKED_STREAMS |
124 ENABLE_CONNECT_PROTOCOL |
125 H3_DATAGRAM
126 ) {
127 return Ok(Validation::Valid);
128 }
129
130 h3::validate_varint(id)
131}
132
133fn settings_type_suggestor(val: &str) -> SuggestionResult<Vec<String>> {
134 let suggestions = [
135 QPACK_MAX_TABLE_CAPACITY,
136 MAX_FIELD_SECTION_SIZE,
137 QPACK_BLOCKED_STREAMS,
138 ENABLE_CONNECT_PROTOCOL,
139 H3_DATAGRAM,
140 ];
141
142 squish_suggester(&suggestions, val)
143}