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 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 };
67
68 Ok(action)
69}
70
71fn settings_read_loop() -> RawSettings {
72 let mut settings = vec![];
73
74 loop {
75 let ty = match Text::new("setting type:")
76 .with_validator(validate_setting_type)
77 .with_autocomplete(&settings_type_suggestor)
78 .with_help_message("type 'q!' to stop adding settings")
79 .prompt()
80 {
81 Ok(h) => {
82 if h == "q!" {
83 break;
84 }
85
86 h
87 },
88 Err(_) => {
89 println!("An error happened, stopping.");
90 break;
91 },
92 };
93
94 let ty = match ty.as_str() {
95 QPACK_MAX_TABLE_CAPACITY => 0x1,
96 MAX_FIELD_SECTION_SIZE => 0x6,
97 QPACK_BLOCKED_STREAMS => 0x7,
98 ENABLE_CONNECT_PROTOCOL => 0x8,
99 H3_DATAGRAM => 0x33,
100
101 v => v.parse::<u64>().unwrap(),
102 };
103
104 let value = Text::new("setting value:")
105 .with_validator(h3::validate_varint)
106 .prompt()
107 .expect("An error happened, stopping.")
108 .parse::<u64>()
109 .unwrap();
110
111 settings.push((ty, value));
112 }
113
114 settings
115}
116
117fn validate_setting_type(id: &str) -> SuggestionResult<Validation> {
118 if matches!(
119 id,
120 "q!" | QPACK_MAX_TABLE_CAPACITY |
121 MAX_FIELD_SECTION_SIZE |
122 QPACK_BLOCKED_STREAMS |
123 ENABLE_CONNECT_PROTOCOL |
124 H3_DATAGRAM
125 ) {
126 return Ok(Validation::Valid);
127 }
128
129 h3::validate_varint(id)
130}
131
132fn settings_type_suggestor(val: &str) -> SuggestionResult<Vec<String>> {
133 let suggestions = [
134 QPACK_MAX_TABLE_CAPACITY,
135 MAX_FIELD_SECTION_SIZE,
136 QPACK_BLOCKED_STREAMS,
137 ENABLE_CONNECT_PROTOCOL,
138 H3_DATAGRAM,
139 ];
140
141 squish_suggester(&suggestions, val)
142}