blob: 0f786f4ee15d9ff31438c9bcd2da54920e4df588 [file] [log] [blame]
Hasnain Lakhani42d0b712025-07-17 19:57:05 -07001// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18/// Configuration for Thrift protocols.
19#[derive(Debug, Clone)]
20pub struct TConfiguration {
21 max_message_size: Option<usize>,
22 max_frame_size: Option<usize>,
23 max_recursion_depth: Option<usize>,
24 max_container_size: Option<usize>,
25 max_string_size: Option<usize>,
26}
27
28impl TConfiguration {
29 // this value is used consistently across all Thrift libraries
30 pub const DEFAULT_MAX_MESSAGE_SIZE: usize = 100 * 1024 * 1024;
31
32 // this value is used consistently across all Thrift libraries
33 pub const DEFAULT_MAX_FRAME_SIZE: usize = 16_384_000;
34
35 pub const DEFAULT_RECURSION_LIMIT: usize = 64;
36
37 pub const DEFAULT_CONTAINER_LIMIT: Option<usize> = None;
38
39 pub const DEFAULT_STRING_LIMIT: usize = 100 * 1024 * 1024;
40
41 pub fn no_limits() -> Self {
42 Self {
43 max_message_size: None,
44 max_frame_size: None,
45 max_recursion_depth: None,
46 max_container_size: None,
47 max_string_size: None,
48 }
49 }
50
51 pub fn max_message_size(&self) -> Option<usize> {
52 self.max_message_size
53 }
54
55 pub fn max_frame_size(&self) -> Option<usize> {
56 self.max_frame_size
57 }
58
59 pub fn max_recursion_depth(&self) -> Option<usize> {
60 self.max_recursion_depth
61 }
62
63 pub fn max_container_size(&self) -> Option<usize> {
64 self.max_container_size
65 }
66
67 pub fn max_string_size(&self) -> Option<usize> {
68 self.max_string_size
69 }
70
71 pub fn builder() -> TConfigurationBuilder {
72 TConfigurationBuilder::default()
73 }
74}
75
76impl Default for TConfiguration {
77 fn default() -> Self {
78 Self {
79 max_message_size: Some(Self::DEFAULT_MAX_MESSAGE_SIZE),
80 max_frame_size: Some(Self::DEFAULT_MAX_FRAME_SIZE),
81 max_recursion_depth: Some(Self::DEFAULT_RECURSION_LIMIT),
82 max_container_size: Self::DEFAULT_CONTAINER_LIMIT,
83 max_string_size: Some(Self::DEFAULT_STRING_LIMIT),
84 }
85 }
86}
87
88#[derive(Debug, Default)]
89pub struct TConfigurationBuilder {
90 config: TConfiguration,
91}
92
93impl TConfigurationBuilder {
94 pub fn max_message_size(mut self, limit: Option<usize>) -> Self {
95 self.config.max_message_size = limit;
96 self
97 }
98
99 pub fn max_frame_size(mut self, limit: Option<usize>) -> Self {
100 self.config.max_frame_size = limit;
101 self
102 }
103
104 pub fn max_recursion_depth(mut self, limit: Option<usize>) -> Self {
105 self.config.max_recursion_depth = limit;
106 self
107 }
108
109 pub fn max_container_size(mut self, limit: Option<usize>) -> Self {
110 self.config.max_container_size = limit;
111 self
112 }
113
114 pub fn max_string_size(mut self, limit: Option<usize>) -> Self {
115 self.config.max_string_size = limit;
116 self
117 }
118
119 pub fn build(self) -> crate::Result<TConfiguration> {
120 if let (Some(frame_size), Some(message_size)) =
121 (self.config.max_frame_size, self.config.max_message_size)
122 {
123 if frame_size > message_size {
124 // FIXME: This should probably be a different error type.
125 return Err(crate::Error::Application(crate::ApplicationError::new(
126 crate::ApplicationErrorKind::Unknown,
127 format!(
128 "Invalid configuration: max_frame_size ({}) cannot exceed max_message_size ({})",
129 frame_size, message_size
130 ),
131 )));
132 }
133 }
134
135 Ok(self.config)
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn test_custom_configuration_builder() {
145 let config = TConfiguration::builder()
146 .max_message_size(Some(1024))
147 .max_frame_size(Some(512))
148 .max_recursion_depth(Some(10))
149 .max_container_size(Some(100))
150 .max_string_size(Some(256))
151 .build()
152 .unwrap();
153
154 assert_eq!(config.max_message_size(), Some(1024));
155 assert_eq!(config.max_frame_size(), Some(512));
156 assert_eq!(config.max_recursion_depth(), Some(10));
157 assert_eq!(config.max_container_size(), Some(100));
158 assert_eq!(config.max_string_size(), Some(256));
159 }
160
161 #[test]
162 fn test_invalid_configuration() {
163 // Test that builder catches invalid configurations
164 let result = TConfiguration::builder()
165 .max_frame_size(Some(1000))
166 .max_message_size(Some(500)) // frame size > message size is invalid
167 .build();
168
169 assert!(result.is_err());
170 match result {
171 Err(crate::Error::Application(e)) => {
172 assert!(e.message.contains("max_frame_size"));
173 assert!(e.message.contains("cannot exceed max_message_size"));
174 }
175 _ => panic!("Expected Application error"),
176 }
177 }
178}