-
Notifications
You must be signed in to change notification settings - Fork 19
/
build.rs
117 lines (101 loc) · 3.19 KB
/
build.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
///
/// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
///
/// Licensed under the Apache License, Version 2.0 (the "License").
/// You may not use this file except in compliance with the License.
/// A copy of the License is located at
///
/// http://aws.amazon.com/apache2.0
///
/// or in the "license" file accompanying this file. This file is distributed
/// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
/// express or implied. See the License for the specific language governing
/// permissions and limitations under the License.
///
use std::env;
use std::fs::File;
use std::io::Write;
const CR: u8 = b'\r';
const LF: u8 = b'\n';
const SP: u8 = b' ';
const HT: u8 = b'\t';
const DEL: u8 = 127;
const NIL: u8 = 0;
const TCHAR: &[u8] = b"-_.!#$%&'*+^`|~";
fn format_char(b: u8) -> String {
use std::fmt::Write;
let mut str = String::new();
match b {
b'\r' => str.push_str("\\r"),
b'\n' => str.push_str("\\n"),
b'\t' => str.push_str("\\t"),
_ if is_rfc_vchar(b) => {
str.push(b as char);
}
_ => {
write!(str, "\\{:#04x}", b).expect("Writing to strings is infallible");
}
};
str
}
fn generate_table(name: &str, predicate: fn(u8) -> bool) -> String {
use std::fmt::Write;
let mut t = String::new();
write!(t, "pub static {}: [bool; 256] = [\r\n ", name).ok();
for i in 0..=255_u8 {
write!(t, " {} /* {} */,", (predicate)(i), format_char(i)).ok();
if i % 4 == 3 {
write!(t, "\r\n ").ok();
}
}
write!(t, "];\r\n").ok();
t
}
fn is_valid_uri_char(b: u8) -> bool {
// disable CTL in URL
b > SP && b != DEL
}
fn is_rfc_tchar(b: u8) -> bool {
b.is_ascii_alphanumeric() || TCHAR.contains(&b)
}
fn is_rfc_vchar(b: u8) -> bool {
(SP..DEL).contains(&b)
}
fn is_rfc_obs_text(b: u8) -> bool {
b >= 0x80
}
fn is_rfc_whitespace(b: u8) -> bool {
b == SP || b == HT
}
fn is_bad_http_character(b: u8) -> bool {
// these characters are absolutely unacceptable in header names/values
// it means multi-line headers are not accepted too
b == CR || b == LF || b == NIL
}
type TableGenerator = fn(u8) -> bool;
fn generate_lookup_tables() {
use std::fmt::Write;
let tables: &[(&str, TableGenerator)] = &[
("TCHAR_TABLE", |b| is_rfc_tchar(b)),
("VCHAR", |b| is_rfc_vchar(b)),
("BAD_CHARACTERS", |b| is_bad_http_character(b)),
("RFC_WHITE_SPACE", |b| is_rfc_whitespace(b)),
("VALID_URI_CHARS", |b| is_valid_uri_char(b)),
("HEADER_VALUE_CHARS", |b| {
is_rfc_vchar(b) || is_rfc_obs_text(b) || is_rfc_whitespace(b)
}),
];
let mut char_tables = String::new();
for table in tables {
write!(char_tables, "{}", generate_table(table.0, table.1))
.expect("Writing to strings is infallible");
}
let out_dir = env::var("OUT_DIR").expect("OUT_DIR variable is not set");
let mut file =
File::create(format!("{}/char_tables.rs", out_dir)).expect("Cannot open file for writing");
file.write_all(char_tables.as_bytes())
.expect("Cannot write to file");
}
fn main() {
generate_lookup_tables();
}