Coverage Report

Created: 2026-09-03 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/thrift/lib/rs/src/configuration.rs
Line
Count
Source
1
// 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)]
20
pub 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
28
impl 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
0
    pub fn no_limits() -> Self {
42
0
        Self {
43
0
            max_message_size: None,
44
0
            max_frame_size: None,
45
0
            max_recursion_depth: None,
46
0
            max_container_size: None,
47
0
            max_string_size: None,
48
0
        }
49
0
    }
50
51
2.75M
    pub fn max_message_size(&self) -> Option<usize> {
52
2.75M
        self.max_message_size
53
2.75M
    }
54
55
0
    pub fn max_frame_size(&self) -> Option<usize> {
56
0
        self.max_frame_size
57
0
    }
58
59
1.78M
    pub fn max_recursion_depth(&self) -> Option<usize> {
60
1.78M
        self.max_recursion_depth
61
1.78M
    }
62
63
2.75M
    pub fn max_container_size(&self) -> Option<usize> {
64
2.75M
        self.max_container_size
65
2.75M
    }
66
67
8.83M
    pub fn max_string_size(&self) -> Option<usize> {
68
8.83M
        self.max_string_size
69
8.83M
    }
70
71
28.2k
    pub fn builder() -> TConfigurationBuilder {
72
28.2k
        TConfigurationBuilder::default()
73
28.2k
    }
74
}
75
76
impl Default for TConfiguration {
77
32.8k
    fn default() -> Self {
78
32.8k
        Self {
79
32.8k
            max_message_size: Some(Self::DEFAULT_MAX_MESSAGE_SIZE),
80
32.8k
            max_frame_size: Some(Self::DEFAULT_MAX_FRAME_SIZE),
81
32.8k
            max_recursion_depth: Some(Self::DEFAULT_RECURSION_LIMIT),
82
32.8k
            max_container_size: Self::DEFAULT_CONTAINER_LIMIT,
83
32.8k
            max_string_size: Some(Self::DEFAULT_STRING_LIMIT),
84
32.8k
        }
85
32.8k
    }
86
}
87
88
#[derive(Debug, Default)]
89
pub struct TConfigurationBuilder {
90
    config: TConfiguration,
91
}
92
93
impl TConfigurationBuilder {
94
28.2k
    pub fn max_message_size(mut self, limit: Option<usize>) -> Self {
95
28.2k
        self.config.max_message_size = limit;
96
28.2k
        self
97
28.2k
    }
98
99
28.2k
    pub fn max_frame_size(mut self, limit: Option<usize>) -> Self {
100
28.2k
        self.config.max_frame_size = limit;
101
28.2k
        self
102
28.2k
    }
103
104
0
    pub fn max_recursion_depth(mut self, limit: Option<usize>) -> Self {
105
0
        self.config.max_recursion_depth = limit;
106
0
        self
107
0
    }
108
109
28.2k
    pub fn max_container_size(mut self, limit: Option<usize>) -> Self {
110
28.2k
        self.config.max_container_size = limit;
111
28.2k
        self
112
28.2k
    }
113
114
28.2k
    pub fn max_string_size(mut self, limit: Option<usize>) -> Self {
115
28.2k
        self.config.max_string_size = limit;
116
28.2k
        self
117
28.2k
    }
118
119
28.2k
    pub fn build(self) -> crate::Result<TConfiguration> {
120
28.2k
        if let (Some(frame_size), Some(message_size)) =
121
28.2k
            (self.config.max_frame_size, self.config.max_message_size)
122
        {
123
28.2k
            if frame_size > message_size {
124
                // FIXME: This should probably be a different error type.
125
0
                return Err(crate::Error::Application(crate::ApplicationError::new(
126
0
                    crate::ApplicationErrorKind::Unknown,
127
0
                    format!(
128
0
                        "Invalid configuration: max_frame_size ({}) cannot exceed max_message_size ({})",
129
0
                        frame_size, message_size
130
0
                    ),
131
0
                )));
132
28.2k
            }
133
0
        }
134
135
28.2k
        Ok(self.config)
136
28.2k
    }
137
}
138
139
#[cfg(test)]
140
mod 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
}