Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/rust/htp/src/c_api/config.rs
Line
Count
Source
1
#![deny(missing_docs)]
2
use crate::{
3
    config::{Config, HtpServerPersonality, HtpUrlEncodingHandling},
4
    hook::{DataExternalCallbackFn, TxCreateCallbackFn, TxDestroyCallbackFn, TxExternalCallbackFn},
5
    HtpStatus,
6
};
7
use std::convert::TryInto;
8
9
/// Creates a new configuration structure. Configuration structures created at
10
/// configuration time must not be changed afterwards in order to support lock-less
11
/// copying.
12
#[no_mangle]
13
40
pub extern "C" fn htp_config_create() -> *mut Config {
14
40
    let cfg: Config = Config::default();
15
40
    let b = Box::new(cfg);
16
40
    Box::into_raw(b)
17
40
}
18
19
/// Destroy a configuration structure.
20
/// # Safety
21
/// This function is unsafe because improper use may lead to memory problems. For example, a double-free may occur if the function is called twice on the same raw pointer.
22
#[no_mangle]
23
0
pub unsafe extern "C" fn htp_config_destroy(cfg: *mut Config) {
24
0
    if !cfg.is_null() {
25
0
        drop(Box::from_raw(cfg));
26
0
    }
27
0
}
28
29
/// Registers a REQUEST_BODY_DATA callback.
30
/// # Safety
31
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
32
#[no_mangle]
33
40
pub unsafe extern "C" fn htp_config_register_request_body_data(
34
40
    cfg: *mut Config, cbk_fn: DataExternalCallbackFn,
35
40
) {
36
40
    if let Some(cfg) = cfg.as_mut() {
37
40
        cfg.hook_request_body_data.register_extern(cbk_fn)
38
0
    }
39
40
}
40
41
/// Registers a REQUEST_COMPLETE callback.
42
/// # Safety
43
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
44
#[no_mangle]
45
40
pub unsafe extern "C" fn htp_config_register_request_complete(
46
40
    cfg: *mut Config, cbk_fn: TxExternalCallbackFn,
47
40
) {
48
40
    if let Some(cfg) = cfg.as_mut() {
49
40
        cfg.hook_request_complete.register_extern(cbk_fn)
50
0
    }
51
40
}
52
53
/// Registers a REQUEST_HEADER_DATA callback.
54
/// # Safety
55
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
56
#[no_mangle]
57
40
pub unsafe extern "C" fn htp_config_register_request_header_data(
58
40
    cfg: *mut Config, cbk_fn: DataExternalCallbackFn,
59
40
) {
60
40
    if let Some(cfg) = cfg.as_mut() {
61
40
        cfg.hook_request_header_data.register_extern(cbk_fn)
62
0
    }
63
40
}
64
65
/// Registers a REQUEST_LINE callback.
66
/// # Safety
67
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
68
#[no_mangle]
69
40
pub unsafe extern "C" fn htp_config_register_request_line(
70
40
    cfg: *mut Config, cbk_fn: TxExternalCallbackFn,
71
40
) {
72
40
    if let Some(cfg) = cfg.as_mut() {
73
40
        cfg.hook_request_line.register_extern(cbk_fn)
74
0
    }
75
40
}
76
77
/// Registers a tx create callback, which is invoked every time a new
78
/// request begins and before any parsing is done.
79
/// # Safety
80
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
81
#[no_mangle]
82
40
pub unsafe extern "C" fn htp_config_register_tx_create(
83
40
    cfg: *mut Config, cbk_fn: TxCreateCallbackFn,
84
40
) {
85
40
    if let Some(cfg) = cfg.as_mut() {
86
40
        cfg.hook_tx_create = Some(cbk_fn);
87
40
    }
88
40
}
89
90
/// Registers a tx destroy callback, which is invoked every time a tx is dropped
91
/// # Safety
92
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
93
#[no_mangle]
94
40
pub unsafe extern "C" fn htp_config_register_tx_destroy(
95
40
    cfg: *mut Config, cbk_fn: TxDestroyCallbackFn,
96
40
) {
97
40
    if let Some(cfg) = cfg.as_mut() {
98
40
        cfg.hook_tx_destroy = Some(cbk_fn);
99
40
    }
100
40
}
101
102
/// Registers a REQUEST_START callback, which is invoked every time a new
103
/// request begins and before any parsing is done.
104
/// # Safety
105
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
106
#[no_mangle]
107
40
pub unsafe extern "C" fn htp_config_register_request_start(
108
40
    cfg: *mut Config, cbk_fn: TxExternalCallbackFn,
109
40
) {
110
40
    if let Some(cfg) = cfg.as_mut() {
111
40
        cfg.hook_request_start.register_extern(cbk_fn)
112
0
    }
113
40
}
114
115
/// Registers a HTP_REQUEST_TRAILER callback.
116
/// # Safety
117
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
118
#[no_mangle]
119
40
pub unsafe extern "C" fn htp_config_register_request_trailer(
120
40
    cfg: *mut Config, cbk_fn: TxExternalCallbackFn,
121
40
) {
122
40
    if let Some(cfg) = cfg.as_mut() {
123
40
        cfg.hook_request_trailer.register_extern(cbk_fn)
124
0
    }
125
40
}
126
127
/// Registers a REQUEST_TRAILER_DATA callback.
128
/// # Safety
129
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
130
#[no_mangle]
131
40
pub unsafe extern "C" fn htp_config_register_request_trailer_data(
132
40
    cfg: *mut Config, cbk_fn: DataExternalCallbackFn,
133
40
) {
134
40
    if let Some(cfg) = cfg.as_mut() {
135
40
        cfg.hook_request_trailer_data.register_extern(cbk_fn)
136
0
    }
137
40
}
138
139
/// Registers a RESPONSE_BODY_DATA callback.
140
/// # Safety
141
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
142
#[no_mangle]
143
40
pub unsafe extern "C" fn htp_config_register_response_body_data(
144
40
    cfg: *mut Config, cbk_fn: DataExternalCallbackFn,
145
40
) {
146
40
    if let Some(cfg) = cfg.as_mut() {
147
40
        cfg.hook_response_body_data.register_extern(cbk_fn)
148
0
    }
149
40
}
150
151
/// Registers a RESPONSE_COMPLETE callback.
152
/// # Safety
153
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
154
#[no_mangle]
155
40
pub unsafe extern "C" fn htp_config_register_response_complete(
156
40
    cfg: *mut Config, cbk_fn: TxExternalCallbackFn,
157
40
) {
158
40
    if let Some(cfg) = cfg.as_mut() {
159
40
        cfg.hook_response_complete.register_extern(cbk_fn)
160
0
    }
161
40
}
162
163
/// Registers a RESPONSE_HEADER_DATA callback.
164
/// # Safety
165
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
166
#[no_mangle]
167
40
pub unsafe extern "C" fn htp_config_register_response_header_data(
168
40
    cfg: *mut Config, cbk_fn: DataExternalCallbackFn,
169
40
) {
170
40
    if let Some(cfg) = cfg.as_mut() {
171
40
        cfg.hook_response_header_data.register_extern(cbk_fn)
172
0
    }
173
40
}
174
175
/// Registers a RESPONSE_START callback.
176
/// # Safety
177
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
178
#[no_mangle]
179
40
pub unsafe extern "C" fn htp_config_register_response_start(
180
40
    cfg: *mut Config, cbk_fn: TxExternalCallbackFn,
181
40
) {
182
40
    if let Some(cfg) = cfg.as_mut() {
183
40
        cfg.hook_response_start.register_extern(cbk_fn)
184
0
    }
185
40
}
186
187
/// Registers a RESPONSE_TRAILER callback.
188
/// # Safety
189
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
190
#[no_mangle]
191
40
pub unsafe extern "C" fn htp_config_register_response_trailer(
192
40
    cfg: *mut Config, cbk_fn: TxExternalCallbackFn,
193
40
) {
194
40
    if let Some(cfg) = cfg.as_mut() {
195
40
        cfg.hook_response_trailer.register_extern(cbk_fn)
196
0
    }
197
40
}
198
199
/// Registers a RESPONSE_TRAILER_DATA callback.
200
/// # Safety
201
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
202
#[no_mangle]
203
40
pub unsafe extern "C" fn htp_config_register_response_trailer_data(
204
40
    cfg: *mut Config, cbk_fn: DataExternalCallbackFn,
205
40
) {
206
40
    if let Some(cfg) = cfg.as_mut() {
207
40
        cfg.hook_response_trailer_data.register_extern(cbk_fn)
208
0
    }
209
40
}
210
211
/// Configures whether backslash characters are treated as path segment separators. They
212
/// are not on Unix systems, but are on Windows systems. If this setting is enabled, a path
213
/// such as "/one\two/three" will be converted to "/one/two/three".
214
/// # Safety
215
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
216
#[no_mangle]
217
0
pub unsafe extern "C" fn htp_config_set_backslash_convert_slashes(
218
0
    cfg: *mut Config, enabled: libc::c_int,
219
0
) {
220
0
    if let Some(cfg) = cfg.as_mut() {
221
0
        cfg.set_backslash_convert_slashes(enabled == 1)
222
0
    }
223
0
}
224
225
/// Sets the replacement character that will be used to in the lossy best-fit
226
/// mapping from multi-byte to single-byte streams. The question mark character
227
/// is used as the default replacement byte.
228
/// # Safety
229
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
230
#[no_mangle]
231
0
pub unsafe extern "C" fn htp_config_set_bestfit_replacement_byte(cfg: *mut Config, b: libc::c_int) {
232
0
    if let Some(cfg) = cfg.as_mut() {
233
0
        cfg.set_bestfit_replacement_byte(b as u8)
234
0
    }
235
0
}
236
237
/// Configures the maximum compression bomb size LibHTP will decompress.
238
/// # Safety
239
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
240
#[no_mangle]
241
40
pub unsafe extern "C" fn htp_config_set_compression_bomb_limit(
242
40
    cfg: *mut Config, bomblimit: libc::size_t,
243
40
) {
244
40
    if let Ok(bomblimit) = bomblimit.try_into() {
245
40
        if let Some(cfg) = cfg.as_mut() {
246
40
            cfg.compression_options.set_bomb_limit(bomblimit)
247
0
        }
248
0
    }
249
40
}
250
251
/// Configures the maximum number of compression bombs LibHTP will decompress.
252
/// # Safety
253
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
254
#[no_mangle]
255
0
pub unsafe extern "C" fn htp_config_set_max_nb_compression_bombs(
256
0
    cfg: *mut Config, max_bombs: libc::size_t,
257
0
) {
258
0
    if let Ok(max_bombs) = max_bombs.try_into() {
259
0
        if let Some(cfg) = cfg.as_mut() {
260
0
            cfg.compression_options.set_max_bombs(max_bombs)
261
0
        }
262
0
    }
263
0
}
264
265
/// Configures the maximum compression time LibHTP will allow.
266
/// # Safety
267
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
268
#[no_mangle]
269
40
pub unsafe extern "C" fn htp_config_set_compression_time_limit(
270
40
    cfg: *mut Config, timelimit: libc::c_uint,
271
40
) {
272
40
    if let Some(cfg) = cfg.as_mut() {
273
40
        cfg.compression_options.set_time_limit(timelimit)
274
0
    }
275
40
}
276
277
/// Configures whether input data will be converted to lowercase. Useful for handling servers with
278
/// case-insensitive filesystems.
279
/// # Safety
280
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
281
#[no_mangle]
282
0
pub unsafe extern "C" fn htp_config_set_convert_lowercase(cfg: *mut Config, enabled: libc::c_int) {
283
0
    if let Some(cfg) = cfg.as_mut() {
284
0
        cfg.set_convert_lowercase(enabled == 1)
285
0
    }
286
0
}
287
288
/// Configures the maximum size of the buffer LibHTP will use when all data is not available
289
/// in the current buffer (e.g., a very long header line that might span several packets). This
290
/// limit is controlled by the field_limit parameter.
291
/// # Safety
292
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
293
#[no_mangle]
294
40
pub unsafe extern "C" fn htp_config_set_field_limit(cfg: *mut Config, field_limit: libc::size_t) {
295
40
    if let Some(cfg) = cfg.as_mut() {
296
40
        cfg.set_field_limit(field_limit)
297
0
    }
298
40
}
299
300
/// Configures the maximum memlimit LibHTP will pass to liblzma.
301
/// # Safety
302
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
303
#[no_mangle]
304
40
pub unsafe extern "C" fn htp_config_set_lzma_memlimit(cfg: *mut Config, memlimit: libc::size_t) {
305
40
    if let Some(cfg) = cfg.as_mut() {
306
40
        cfg.compression_options.set_lzma_memlimit(memlimit)
307
0
    }
308
40
}
309
310
/// Configures the maximum number of lzma layers to pass to the decompressor.
311
/// # Safety
312
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
313
#[no_mangle]
314
40
pub unsafe extern "C" fn htp_config_set_lzma_layers(cfg: *mut Config, limit: libc::c_int) {
315
40
    if let Some(cfg) = cfg.as_mut() {
316
40
        cfg.compression_options.set_lzma_layers(if limit <= 0 {
317
40
            None
318
        } else {
319
0
            limit.try_into().ok()
320
        })
321
0
    }
322
40
}
323
324
/// Configures the maximum number of live transactions per connection
325
/// # Safety
326
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
327
#[no_mangle]
328
40
pub unsafe extern "C" fn htp_config_set_max_tx(cfg: *mut Config, limit: u32) {
329
40
    if let Some(cfg) = cfg.as_mut() {
330
40
        cfg.max_tx = limit;
331
40
    }
332
40
}
333
334
/// Configures the maximum number of headers in one transaction
335
/// # Safety
336
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
337
#[no_mangle]
338
40
pub unsafe extern "C" fn htp_config_set_number_headers_limit(cfg: *mut Config, limit: u32) {
339
40
    if let Some(cfg) = cfg.as_mut() {
340
40
        cfg.number_headers_limit = limit;
341
40
    }
342
40
}
343
344
/// Configures how the server reacts to encoded NUL bytes. Some servers will stop at
345
/// at NUL, while some will respond with 400 or 404. When the termination option is not
346
/// used, the NUL byte will remain in the path.
347
/// # Safety
348
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
349
#[no_mangle]
350
0
pub unsafe extern "C" fn htp_config_set_nul_encoded_terminates(
351
0
    cfg: *mut Config, enabled: libc::c_int,
352
0
) {
353
0
    if let Some(cfg) = cfg.as_mut() {
354
0
        cfg.set_nul_encoded_terminates(enabled == 1)
355
0
    }
356
0
}
357
358
/// Configures the handling of raw NUL bytes. If enabled, raw NUL terminates strings.
359
/// # Safety
360
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
361
#[no_mangle]
362
0
pub unsafe extern "C" fn htp_config_set_nul_raw_terminates(cfg: *mut Config, enabled: libc::c_int) {
363
0
    if let Some(cfg) = cfg.as_mut() {
364
0
        cfg.set_nul_raw_terminates(enabled == 1)
365
0
    }
366
0
}
367
368
/// Enable or disable request cookie parsing. Enabled by default.
369
/// # Safety
370
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
371
#[no_mangle]
372
40
pub unsafe extern "C" fn htp_config_set_parse_request_cookies(
373
40
    _cfg: *mut Config, _parse_request_cookies: libc::c_int,
374
40
) {
375
    // do nothing, but keep API
376
40
}
377
378
/// Configures whether consecutive path segment separators will be compressed. When enabled, a path
379
/// such as "/one//two" will be normalized to "/one/two". Backslash conversion and path segment separator
380
/// decoding are carried out before compression. For example, the path "/one\\/two\/%5cthree/%2f//four"
381
/// will be converted to "/one/two/three/four" (assuming all 3 options are enabled).
382
/// # Safety
383
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
384
#[no_mangle]
385
0
pub unsafe extern "C" fn htp_config_set_path_separators_compress(
386
0
    cfg: *mut Config, enabled: libc::c_int,
387
0
) {
388
0
    if let Some(cfg) = cfg.as_mut() {
389
0
        cfg.set_path_separators_compress(enabled == 1)
390
0
    }
391
0
}
392
393
/// Configures whether plus characters are converted to spaces when decoding URL-encoded strings. This
394
/// is appropriate to do for parameters, but not for URLs. Only applies to contexts where decoding
395
/// is taking place.
396
/// # Safety
397
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
398
#[no_mangle]
399
40
pub unsafe extern "C" fn htp_config_set_plusspace_decode(cfg: *mut Config, enabled: libc::c_int) {
400
40
    if let Some(cfg) = cfg.as_mut() {
401
40
        cfg.set_plusspace_decode(enabled == 1)
402
0
    }
403
40
}
404
405
/// Configures whether encoded path segment separators will be decoded. Apache does not do
406
/// this by default, but IIS does. If enabled, a path such as "/one%2ftwo" will be normalized
407
/// to "/one/two". If the backslash_separators option is also enabled, encoded backslash
408
/// characters will be converted too (and subsequently normalized to forward slashes).
409
/// # Safety
410
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
411
#[no_mangle]
412
0
pub unsafe extern "C" fn htp_config_set_path_separators_decode(
413
0
    cfg: *mut Config, enabled: libc::c_int,
414
0
) {
415
0
    if let Some(cfg) = cfg.as_mut() {
416
0
        cfg.set_path_separators_decode(enabled == 1)
417
0
    }
418
0
}
419
420
/// Configures whether request data is decompressed
421
/// # Safety
422
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
423
#[no_mangle]
424
40
pub unsafe extern "C" fn htp_config_set_request_decompression(
425
40
    cfg: *mut Config, enabled: libc::c_int,
426
40
) {
427
40
    if let Some(cfg) = cfg.as_mut() {
428
40
        cfg.set_request_decompression(enabled == 1)
429
0
    }
430
40
}
431
432
/// Configures many layers of compression we try to decompress.
433
/// # Safety
434
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
435
#[no_mangle]
436
0
pub unsafe extern "C" fn htp_config_set_decompression_layer_limit(
437
0
    cfg: *mut Config, limit: libc::c_int,
438
0
) {
439
0
    if let Some(cfg) = cfg.as_mut() {
440
0
        cfg.set_decompression_layer_limit(if limit <= 0 {
441
0
            None
442
        } else {
443
0
            limit.try_into().ok()
444
        })
445
0
    }
446
0
}
447
448
/// Enable or disable allowing spaces in URIs. Disabled by default.
449
/// # Safety
450
/// When calling this method the given cfg must be initialized or NULL.
451
#[no_mangle]
452
40
pub unsafe extern "C" fn htp_config_set_allow_space_uri(cfg: *mut Config, allow_space: bool) {
453
40
    if let Some(cfg) = cfg.as_mut() {
454
40
        cfg.set_allow_space_uri(allow_space)
455
0
    }
456
40
}
457
458
/// Configure desired server personality.
459
/// # Safety
460
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
461
#[no_mangle]
462
0
pub unsafe extern "C" fn htp_config_set_server_personality(
463
0
    cfg: *mut Config, personality: HtpServerPersonality,
464
0
) -> HtpStatus {
465
0
    cfg.as_mut()
466
0
        .map(|cfg| cfg.set_server_personality(personality).into())
467
0
        .unwrap_or(HtpStatus::ERROR)
468
0
}
469
470
/// Configures whether %u-encoded sequences are decoded. Such sequences
471
/// will be treated as invalid URL encoding if decoding is not desirable.
472
/// # Safety
473
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
474
#[no_mangle]
475
0
pub unsafe extern "C" fn htp_config_set_u_encoding_decode(cfg: *mut Config, enabled: libc::c_int) {
476
0
    if let Some(cfg) = cfg.as_mut() {
477
0
        cfg.set_u_encoding_decode(enabled == 1)
478
0
    }
479
0
}
480
481
/// Configures how the server handles to invalid URL encoding.
482
/// # Safety
483
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
484
#[no_mangle]
485
0
pub unsafe extern "C" fn htp_config_set_url_encoding_invalid_handling(
486
0
    cfg: *mut Config, handling: HtpUrlEncodingHandling,
487
0
) {
488
0
    if let Some(cfg) = cfg.as_mut() {
489
0
        cfg.set_url_encoding_invalid_handling(handling)
490
0
    }
491
0
}
492
493
/// Controls whether the data should be treated as UTF-8 and converted to a single-byte
494
/// stream using best-fit mapping.
495
/// # Safety
496
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
497
#[no_mangle]
498
0
pub unsafe extern "C" fn htp_config_set_utf8_convert_bestfit(
499
0
    cfg: *mut Config, enabled: libc::c_int,
500
0
) {
501
0
    if let Some(cfg) = cfg.as_mut() {
502
0
        cfg.set_utf8_convert_bestfit(enabled == 1)
503
0
    }
504
0
}
505
506
/// Configures whether to attempt to decode a double encoded query in the normalized uri
507
/// # Safety
508
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
509
#[no_mangle]
510
0
pub unsafe extern "C" fn htp_config_set_double_decode_normalized_query(
511
0
    cfg: *mut Config, set: bool,
512
0
) {
513
0
    if let Some(cfg) = cfg.as_mut() {
514
0
        cfg.set_double_decode_normalized_query(set)
515
0
    }
516
0
}
517
518
/// Configures whether to attempt to decode a double encoded path in the normalized uri
519
/// # Safety
520
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
521
#[no_mangle]
522
0
pub unsafe extern "C" fn htp_config_set_double_decode_normalized_path(cfg: *mut Config, set: bool) {
523
0
    if let Some(cfg) = cfg.as_mut() {
524
0
        cfg.set_double_decode_normalized_path(set)
525
0
    }
526
0
}
527
528
/// Configures whether to normalize URIs into a complete or partial form.
529
/// Pass `true` to use complete normalized URI or `false` to use partials.
530
/// # Safety
531
/// When calling this method, you have to ensure that cfg is either properly initialized or NULL
532
#[no_mangle]
533
40
pub unsafe extern "C" fn htp_config_set_normalized_uri_include_all(cfg: *mut Config, set: bool) {
534
40
    if let Some(cfg) = cfg.as_mut() {
535
40
        cfg.set_normalized_uri_include_all(set)
536
0
    }
537
40
}