1 // Copyright (c) 2023 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 #![rustfmt::skip] 15 16 use std::collections::{HashMap, VecDeque}; 17 18 /// The [`Dynamic Table`][dynamic_table] implementation of [QPACK]. 19 /// 20 /// [dynamic_table]: https://www.rfc-editor.org/rfc/rfc9204.html#name-dynamic-table 21 /// [QPACK]: https://www.rfc-editor.org/rfc/rfc9204.html 22 /// # Introduction 23 /// The dynamic table consists of a list of field lines maintained in first-in, first-out order. 24 /// A QPACK encoder and decoder share a dynamic table that is initially empty. 25 /// The encoder adds entries to the dynamic table and sends them to the decoder via instructions on 26 /// the encoder stream 27 /// 28 /// The dynamic table can contain duplicate entries (i.e., entries with the same name and same value). 29 /// Therefore, duplicate entries MUST NOT be treated as an error by the decoder. 30 /// 31 /// Dynamic table entries can have empty values. 32 33 pub(crate) struct TableSearcher<'a> { 34 dynamic: &'a DynamicTable, 35 } 36 37 impl<'a> TableSearcher<'a> { new(dynamic: &'a DynamicTable) -> Self38 pub(crate) fn new(dynamic: &'a DynamicTable) -> Self { 39 Self { dynamic } 40 } 41 42 /// Searches index in static and dynamic tables. find_index_static(&self, header: &Field, value: &str) -> Option<TableIndex>43 pub(crate) fn find_index_static(&self, header: &Field, value: &str) -> Option<TableIndex> { 44 match StaticTable::index(header, value) { 45 x @ Some(TableIndex::Field(_)) => x, 46 _ => Some(TableIndex::None), 47 } 48 } 49 find_index_name_static(&self, header: &Field, value: &str) -> Option<TableIndex>50 pub(crate) fn find_index_name_static(&self, header: &Field, value: &str) -> Option<TableIndex> { 51 match StaticTable::index(header, value) { 52 x @ Some(TableIndex::FieldName(_)) => x, 53 _ => Some(TableIndex::None), 54 } 55 } 56 find_index_dynamic(&self, header: &Field, value: &str) -> Option<TableIndex>57 pub(crate) fn find_index_dynamic(&self, header: &Field, value: &str) -> Option<TableIndex> { 58 match self.dynamic.index(header, value) { 59 x @ Some(TableIndex::Field(_)) => x, 60 _ => Some(TableIndex::None), 61 } 62 } 63 find_index_name_dynamic( &self, header: &Field, value: &str, ) -> Option<TableIndex>64 pub(crate) fn find_index_name_dynamic( 65 &self, 66 header: &Field, 67 value: &str, 68 ) -> Option<TableIndex> { 69 match self.dynamic.index_name(header, value) { 70 x @ Some(TableIndex::FieldName(_)) => x, 71 _ => Some(TableIndex::None), 72 } 73 } 74 find_field_static(&self, index: usize) -> Option<(Field, String)>75 pub(crate) fn find_field_static(&self, index: usize) -> Option<(Field, String)> { 76 match StaticTable::field(index) { 77 x @ Some((_, _)) => x, 78 _ => None, 79 } 80 } 81 find_field_name_static(&self, index: usize) -> Option<Field>82 pub(crate) fn find_field_name_static(&self, index: usize) -> Option<Field> { 83 StaticTable::field_name(index) 84 } 85 find_field_dynamic(&self, index: usize) -> Option<(Field, String)>86 pub(crate) fn find_field_dynamic(&self, index: usize) -> Option<(Field, String)> { 87 self.dynamic.field(index) 88 } 89 find_field_name_dynamic(&self, index: usize) -> Option<Field>90 pub(crate) fn find_field_name_dynamic(&self, index: usize) -> Option<Field> { 91 self.dynamic.field_name(index) 92 } 93 } 94 95 pub struct DynamicTable { 96 queue: VecDeque<(Field, String)>, 97 // The size of the dynamic table is the sum of the size of its entries 98 size: usize, 99 capacity: usize, 100 pub(crate) insert_count: usize, 101 remove_count: usize, 102 pub(crate) known_received_count: usize, 103 } 104 105 impl DynamicTable { with_empty() -> Self106 pub fn with_empty() -> Self { 107 Self { 108 queue: VecDeque::new(), 109 size: 0, 110 capacity: 0, 111 insert_count: 0, 112 remove_count: 0, 113 known_received_count: 0, 114 } 115 } 116 size(&self) -> usize117 pub(crate) fn size(&self) -> usize { 118 self.size 119 } 120 capacity(&self) -> usize121 pub(crate) fn capacity(&self) -> usize { 122 self.capacity 123 } 124 max_entries(&self) -> usize125 pub(crate) fn max_entries(&self) -> usize { 126 self.capacity / 32 127 } 128 /// Updates `DynamicTable` by a given `Header` and value pair. update(&mut self, field: Field, value: String) -> Option<TableIndex>129 pub(crate) fn update(&mut self, field: Field, value: String) -> Option<TableIndex> { 130 self.insert_count += 1; 131 self.size += field.len() + value.len() + 32; 132 self.queue.push_back((field.clone(), value.clone())); 133 self.fit_size(); 134 self.index(&field, &value) 135 } 136 have_enough_space( &self, field: &Field, value: &String, insert_length: &usize, ) -> bool137 pub(crate) fn have_enough_space( 138 &self, 139 field: &Field, 140 value: &String, 141 insert_length: &usize, 142 ) -> bool { 143 if self.size + field.len() + value.len() + 32 <= self.capacity - insert_length { 144 return true; 145 } else { 146 let mut eviction_space = 0; 147 for (i, (h, v)) in self.queue.iter().enumerate() { 148 if i <= self.known_received_count { 149 eviction_space += h.len() + v.len() + 32; 150 } else { 151 if eviction_space - insert_length >= field.len() + value.len() + 32 { 152 return true; 153 } 154 return false; 155 } 156 if eviction_space - insert_length >= field.len() + value.len() + 32 { 157 return true; 158 } 159 } 160 } 161 false 162 } 163 164 /// Updates `DynamicTable`'s size. update_size(&mut self, max_size: usize)165 pub(crate) fn update_size(&mut self, max_size: usize) { 166 self.capacity = max_size; 167 self.fit_size(); 168 } 169 170 /// Adjusts dynamic table content to fit its size. fit_size(&mut self)171 fn fit_size(&mut self) { 172 while self.size > self.capacity && !self.queue.is_empty() { 173 let (key, string) = self.queue.pop_front().unwrap(); 174 self.remove_count += 1; 175 self.capacity -= key.len() + string.len() + 32; 176 } 177 } 178 179 /// Tries get the index of a `Header`. index(&self, header: &Field, value: &str) -> Option<TableIndex>180 fn index(&self, header: &Field, value: &str) -> Option<TableIndex> { 181 // find latest 182 let mut index = None; 183 for (n, (h, v)) in self.queue.iter().enumerate() { 184 if let (true, true, _) = (header == h, value == v, &index) { 185 index = Some(TableIndex::Field(n + self.remove_count)) 186 } 187 } 188 index 189 } 190 index_name(&self, header: &Field, value: &str) -> Option<TableIndex>191 fn index_name(&self, header: &Field, value: &str) -> Option<TableIndex> { 192 // find latest 193 let mut index = None; 194 for (n, (h, v)) in self.queue.iter().enumerate() { 195 if let (true, _, _) = (header == h, value == v, &index) { 196 index = Some(TableIndex::FieldName(n + self.remove_count)) 197 } 198 } 199 index 200 } 201 field(&self, index: usize) -> Option<(Field, String)>202 pub(crate) fn field(&self, index: usize) -> Option<(Field, String)> { 203 self.queue.get(index - self.remove_count).cloned() 204 } 205 field_name(&self, index: usize) -> Option<Field>206 pub(crate) fn field_name(&self, index: usize) -> Option<Field> { 207 self.queue 208 .get(index - self.remove_count) 209 .map(|(field, _)| field.clone()) 210 } 211 } 212 213 #[derive(PartialEq, Clone)] 214 pub(crate) enum TableIndex { 215 Field(usize), 216 FieldName(usize), 217 None, 218 } 219 220 /// The [`Static Table`][static_table] implementation of [QPACK]. 221 /// 222 /// [static_table]: https://www.rfc-editor.org/rfc/rfc9204.html#static-table 223 /// [QPACK]: https://www.rfc-editor.org/rfc/rfc9204.html 224 /// 225 /// # Introduction 226 /// The static table consists of a predefined list of field lines, 227 /// each of which has a fixed index over time. 228 /// All entries in the static table have a name and a value. 229 /// However, values can be empty (that is, have a length of 0). Each entry is 230 /// identified by a unique index. 231 /// Note that the QPACK static table is indexed from 0, 232 /// whereas the HPACK static table is indexed from 1. 233 /// When the decoder encounters an invalid static table 234 /// index in a field line format, it MUST treat this 235 /// as a connection error of type QpackDecompressionFailed. 236 /// If this index is received on the encoder stream, 237 /// this MUST be treated as a connection error of type QpackEncoderStreamError. 238 /// 239 240 struct StaticTable; 241 242 impl StaticTable { 243 /// Gets a `Field` by the given index. field_name(index: usize) -> Option<Field>244 fn field_name(index: usize) -> Option<Field> { 245 match index { 246 0 => Some(Field::Authority), 247 1 => Some(Field::Path), 248 2 => Some(Field::Other(String::from("age"))), 249 3 => Some(Field::Other(String::from("content-disposition"))), 250 4 => Some(Field::Other(String::from("content-length"))), 251 5 => Some(Field::Other(String::from("cookie"))), 252 6 => Some(Field::Other(String::from("date"))), 253 7 => Some(Field::Other(String::from("etag"))), 254 8 => Some(Field::Other(String::from("if-modified-since"))), 255 9 => Some(Field::Other(String::from("if-none-match"))), 256 10 => Some(Field::Other(String::from("last-modified"))), 257 11 => Some(Field::Other(String::from("link"))), 258 12 => Some(Field::Other(String::from("location"))), 259 13 => Some(Field::Other(String::from("referer"))), 260 14 => Some(Field::Other(String::from("set-cookie"))), 261 15..=21 => Some(Field::Method), 262 22..=23 => Some(Field::Scheme), 263 24..=28 => Some(Field::Status), 264 29..=30 => Some(Field::Other(String::from("accept"))), 265 31 => Some(Field::Other(String::from("accept-encoding"))), 266 32 => Some(Field::Other(String::from("accept-ranges"))), 267 33..=34 => Some(Field::Other(String::from("access-control-allow-headers"))), 268 35 => Some(Field::Other(String::from("access-control-allow-origin"))), 269 36..=41 => Some(Field::Other(String::from("cache-control"))), 270 42..=43 => Some(Field::Other(String::from("content-encoding"))), 271 44..=54 => Some(Field::Other(String::from("content-type"))), 272 55 => Some(Field::Other(String::from("range"))), 273 56..=58 => Some(Field::Other(String::from("strict-transport-security"))), 274 59..=60 => Some(Field::Other(String::from("vary"))), 275 61 => Some(Field::Other(String::from("x-content-type-options"))), 276 62 => Some(Field::Other(String::from("x-xss-protection"))), 277 63..=71 => Some(Field::Status), 278 72 => Some(Field::Other(String::from("accept-language"))), 279 73..=74 => Some(Field::Other(String::from( 280 "access-control-allow-credentials", 281 ))), 282 75 => Some(Field::Other(String::from("access-control-allow-headers"))), 283 76..=78 => Some(Field::Other(String::from("access-control-allow-methods"))), 284 79 => Some(Field::Other(String::from("access-control-expose-headers"))), 285 80 => Some(Field::Other(String::from("access-control-request-headers"))), 286 81..=82 => Some(Field::Other(String::from("access-control-request-method"))), 287 83 => Some(Field::Other(String::from("alt-svc"))), 288 84 => Some(Field::Other(String::from("authorization"))), 289 85 => Some(Field::Other(String::from("content-security-policy"))), 290 86 => Some(Field::Other(String::from("early-data"))), 291 87 => Some(Field::Other(String::from("expect-ct"))), 292 88 => Some(Field::Other(String::from("forwarded"))), 293 89 => Some(Field::Other(String::from("if-range"))), 294 90 => Some(Field::Other(String::from("origin"))), 295 91 => Some(Field::Other(String::from("purpose"))), 296 92 => Some(Field::Other(String::from("server"))), 297 93 => Some(Field::Other(String::from("timing-allow-origin"))), 298 94 => Some(Field::Other(String::from("upgrade-insecure-requests"))), 299 95 => Some(Field::Other(String::from("user-agent"))), 300 96 => Some(Field::Other(String::from("x-forwarded-for"))), 301 97..=98 => Some(Field::Other(String::from("x-frame-options"))), 302 _ => None, 303 } 304 } 305 306 /// Tries to get a `Field` and a value by the given index. field(index: usize) -> Option<(Field, String)>307 fn field(index: usize) -> Option<(Field, String)> { 308 match index { 309 1 => Some((Field::Path, String::from("/"))), 310 2 => Some((Field::Other(String::from("age")), String::from("0"))), 311 4 => Some(( 312 Field::Other(String::from("content-length")), 313 String::from("0"), 314 )), 315 15 => Some((Field::Method, String::from("CONNECT"))), 316 16 => Some((Field::Method, String::from("DELETE"))), 317 17 => Some((Field::Method, String::from("GET"))), 318 18 => Some((Field::Method, String::from("HEAD"))), 319 19 => Some((Field::Method, String::from("OPTIONS"))), 320 20 => Some((Field::Method, String::from("POST"))), 321 21 => Some((Field::Method, String::from("PUT"))), 322 22 => Some((Field::Scheme, String::from("http"))), 323 23 => Some((Field::Scheme, String::from("https"))), 324 24 => Some((Field::Status, String::from("103"))), 325 25 => Some((Field::Status, String::from("200"))), 326 26 => Some((Field::Status, String::from("304"))), 327 27 => Some((Field::Status, String::from("404"))), 328 28 => Some((Field::Status, String::from("503"))), 329 29 => Some((Field::Other(String::from("accept")), String::from("*/*"))), 330 30 => Some(( 331 Field::Other(String::from("accept")), 332 String::from("application/dns-message"), 333 )), 334 31 => Some(( 335 Field::Other(String::from("accept-encoding")), 336 String::from("gzip, deflate, br"), 337 )), 338 32 => Some(( 339 Field::Other(String::from("accept-ranges")), 340 String::from("bytes"), 341 )), 342 33 => Some(( 343 Field::Other(String::from("access-control-allow-headers")), 344 String::from("cache-control"), 345 )), 346 34 => Some(( 347 Field::Other(String::from("access-control-allow-headers")), 348 String::from("content-type"), 349 )), 350 35 => Some(( 351 Field::Other(String::from("access-control-allow-origin")), 352 String::from("*"), 353 )), 354 36 => Some(( 355 Field::Other(String::from("cache-control")), 356 String::from("max-age=0"), 357 )), 358 37 => Some(( 359 Field::Other(String::from("cache-control")), 360 String::from("max-age=2592000"), 361 )), 362 38 => Some(( 363 Field::Other(String::from("cache-control")), 364 String::from("max-age=604800"), 365 )), 366 39 => Some(( 367 Field::Other(String::from("cache-control")), 368 String::from("no-cache"), 369 )), 370 40 => Some(( 371 Field::Other(String::from("cache-control")), 372 String::from("no-store"), 373 )), 374 41 => Some(( 375 Field::Other(String::from("cache-control")), 376 String::from("public, max-age=31536000"), 377 )), 378 42 => Some(( 379 Field::Other(String::from("content-encoding")), 380 String::from("br"), 381 )), 382 43 => Some(( 383 Field::Other(String::from("content-encoding")), 384 String::from("gzip"), 385 )), 386 44 => Some(( 387 Field::Other(String::from("content-type")), 388 String::from("application/dns-message"), 389 )), 390 45 => Some(( 391 Field::Other(String::from("content-type")), 392 String::from("application/javascript"), 393 )), 394 46 => Some(( 395 Field::Other(String::from("content-type")), 396 String::from("application/json"), 397 )), 398 47 => Some(( 399 Field::Other(String::from("content-type")), 400 String::from("application/x-www-form-urlencoded"), 401 )), 402 48 => Some(( 403 Field::Other(String::from("content-type")), 404 String::from("image/gif"), 405 )), 406 49 => Some(( 407 Field::Other(String::from("content-type")), 408 String::from("image/jpeg"), 409 )), 410 50 => Some(( 411 Field::Other(String::from("content-type")), 412 String::from("image/png"), 413 )), 414 51 => Some(( 415 Field::Other(String::from("content-type")), 416 String::from("text/css"), 417 )), 418 52 => Some(( 419 Field::Other(String::from("content-type")), 420 String::from("text/html; charset=utf-8"), 421 )), 422 53 => Some(( 423 Field::Other(String::from("content-type")), 424 String::from("text/plain"), 425 )), 426 54 => Some(( 427 Field::Other(String::from("content-type")), 428 String::from("text/plain;charset=utf-8"), 429 )), 430 55 => Some(( 431 Field::Other(String::from("range")), 432 String::from("bytes=0-"), 433 )), 434 56 => Some(( 435 Field::Other(String::from("strict-transport-security")), 436 String::from("max-age=31536000"), 437 )), 438 57 => Some(( 439 Field::Other(String::from("strict-transport-security")), 440 String::from("max-age=31536000; includesubdomains"), 441 )), 442 58 => Some(( 443 Field::Other(String::from("strict-transport-security")), 444 String::from("max-age=31536000; includesubdomains; preload"), 445 )), 446 59 => Some(( 447 Field::Other(String::from("vary")), 448 String::from("accept-encoding"), 449 )), 450 60 => Some((Field::Other(String::from("vary")), String::from("origin"))), 451 61 => Some(( 452 Field::Other(String::from("x-content-type-options")), 453 String::from("nosniff"), 454 )), 455 62 => Some(( 456 Field::Other(String::from("x-xss-protection")), 457 String::from("1; mode=block"), 458 )), 459 63 => Some((Field::Status, String::from("100"))), 460 64 => Some((Field::Status, String::from("204"))), 461 65 => Some((Field::Status, String::from("206"))), 462 66 => Some((Field::Status, String::from("302"))), 463 67 => Some((Field::Status, String::from("400"))), 464 68 => Some((Field::Status, String::from("403"))), 465 69 => Some((Field::Status, String::from("421"))), 466 70 => Some((Field::Status, String::from("425"))), 467 71 => Some((Field::Status, String::from("500"))), 468 73 => Some(( 469 Field::Other(String::from("access-control-allow-credentials")), 470 String::from("FALSE"), 471 )), 472 74 => Some(( 473 Field::Other(String::from("access-control-allow-credentials")), 474 String::from("TRUE"), 475 )), 476 75 => Some(( 477 Field::Other(String::from("access-control-allow-headers")), 478 String::from("*"), 479 )), 480 76 => Some(( 481 Field::Other(String::from("access-control-allow-methods")), 482 String::from("get"), 483 )), 484 77 => Some(( 485 Field::Other(String::from("access-control-allow-methods")), 486 String::from("get, post, options"), 487 )), 488 78 => Some(( 489 Field::Other(String::from("access-control-allow-methods")), 490 String::from("options"), 491 )), 492 79 => Some(( 493 Field::Other(String::from("access-control-expose-headers")), 494 String::from("content-length"), 495 )), 496 80 => Some(( 497 Field::Other(String::from("access-control-request-headers")), 498 String::from("content-type"), 499 )), 500 81 => Some(( 501 Field::Other(String::from("access-control-request-method")), 502 String::from("get"), 503 )), 504 82 => Some(( 505 Field::Other(String::from("access-control-request-method")), 506 String::from("post"), 507 )), 508 83 => Some((Field::Other(String::from("alt-svc")), String::from("clear"))), 509 85 => Some(( 510 Field::Other(String::from("content-security-policy")), 511 String::from("script-src 'none'; object-src 'none'; base-uri 'none'"), 512 )), 513 86 => Some((Field::Other(String::from("early-data")), String::from("1"))), 514 91 => Some(( 515 Field::Other(String::from("purpose")), 516 String::from("prefetch"), 517 )), 518 93 => Some(( 519 Field::Other(String::from("timing-allow-origin")), 520 String::from("*"), 521 )), 522 94 => Some(( 523 Field::Other(String::from("upgrade-insecure-requests")), 524 String::from("1"), 525 )), 526 97 => Some(( 527 Field::Other(String::from("x-frame-options")), 528 String::from("deny"), 529 )), 530 98 => Some(( 531 Field::Other(String::from("x-frame-options")), 532 String::from("sameorigin"), 533 )), 534 _ => None, 535 } 536 } 537 538 /// Tries to get a `Index` by the given field and value. index(field: &Field, value: &str) -> Option<TableIndex>539 fn index(field: &Field, value: &str) -> Option<TableIndex> { 540 match (field, value) { 541 (Field::Authority, _) => Some(TableIndex::FieldName(0)), 542 (Field::Path, "/") => Some(TableIndex::Field(1)), 543 (Field::Path, _) => Some(TableIndex::FieldName(1)), 544 (Field::Method, "CONNECT") => Some(TableIndex::Field(15)), 545 (Field::Method, "DELETE") => Some(TableIndex::Field(16)), 546 (Field::Method, "GET") => Some(TableIndex::Field(17)), 547 (Field::Method, "HEAD") => Some(TableIndex::Field(18)), 548 (Field::Method, "OPTIONS") => Some(TableIndex::Field(19)), 549 (Field::Method, "POST") => Some(TableIndex::Field(20)), 550 (Field::Method, "PUT") => Some(TableIndex::Field(21)), 551 (Field::Method, _) => Some(TableIndex::FieldName(15)), 552 (Field::Scheme, "http") => Some(TableIndex::Field(22)), 553 (Field::Scheme, "https") => Some(TableIndex::Field(23)), 554 (Field::Scheme, _) => Some(TableIndex::FieldName(22)), 555 (Field::Status, "103") => Some(TableIndex::Field(24)), 556 (Field::Status, "200") => Some(TableIndex::Field(25)), 557 (Field::Status, "304") => Some(TableIndex::Field(26)), 558 (Field::Status, "404") => Some(TableIndex::Field(27)), 559 (Field::Status, "503") => Some(TableIndex::Field(28)), 560 (Field::Status, "100") => Some(TableIndex::Field(63)), 561 (Field::Status, "204") => Some(TableIndex::Field(64)), 562 (Field::Status, "206") => Some(TableIndex::Field(65)), 563 (Field::Status, "302") => Some(TableIndex::Field(66)), 564 (Field::Status, "400") => Some(TableIndex::Field(67)), 565 (Field::Status, "403") => Some(TableIndex::Field(68)), 566 (Field::Status, "421") => Some(TableIndex::Field(69)), 567 (Field::Status, "425") => Some(TableIndex::Field(70)), 568 (Field::Status, "500") => Some(TableIndex::Field(71)), 569 (Field::Status, _) => Some(TableIndex::FieldName(24)), 570 (Field::Other(s), v) => match (s.as_str(), v) { 571 ("age", "0") => Some(TableIndex::Field(2)), 572 ("age", _) => Some(TableIndex::FieldName(2)), 573 ("content-disposition", _) => Some(TableIndex::FieldName(3)), 574 ("content-length", "0") => Some(TableIndex::Field(4)), 575 ("content-length", _) => Some(TableIndex::FieldName(4)), 576 ("cookie", _) => Some(TableIndex::FieldName(5)), 577 ("date", _) => Some(TableIndex::FieldName(6)), 578 ("etag", _) => Some(TableIndex::FieldName(7)), 579 ("if-modified-since", _) => Some(TableIndex::FieldName(8)), 580 ("if-none-match", _) => Some(TableIndex::FieldName(9)), 581 ("last-modified", _) => Some(TableIndex::FieldName(10)), 582 ("link", _) => Some(TableIndex::FieldName(11)), 583 ("location", _) => Some(TableIndex::FieldName(12)), 584 ("referer", _) => Some(TableIndex::FieldName(13)), 585 ("set-cookie", _) => Some(TableIndex::FieldName(14)), 586 ("accept", "*/*") => Some(TableIndex::Field(29)), 587 ("accept", "application/dns-message") => Some(TableIndex::Field(30)), 588 ("accept", _) => Some(TableIndex::FieldName(29)), 589 ("accept-encoding", "gzip, deflate, br") => Some(TableIndex::Field(31)), 590 ("accept-encoding", _) => Some(TableIndex::FieldName(31)), 591 ("accept-ranges", "bytes") => Some(TableIndex::Field(32)), 592 ("accept-ranges", _) => Some(TableIndex::FieldName(32)), 593 ("access-control-allow-headers", "cache-control") => Some(TableIndex::Field(33)), 594 ("access-control-allow-headers", "content-type") => Some(TableIndex::Field(34)), 595 ("access-control-allow-origin", "*") => Some(TableIndex::Field(35)), 596 ("access-control-allow-origin", _) => Some(TableIndex::FieldName(35)), 597 ("cache-control", "max-age=0") => Some(TableIndex::Field(36)), 598 ("cache-control", "max-age=2592000") => Some(TableIndex::Field(37)), 599 ("cache-control", "max-age=604800") => Some(TableIndex::Field(38)), 600 ("cache-control", "no-cache") => Some(TableIndex::Field(39)), 601 ("cache-control", "no-store") => Some(TableIndex::Field(40)), 602 ("cache-control", "public, max-age=31536000") => Some(TableIndex::Field(41)), 603 ("cache-control", _) => Some(TableIndex::FieldName(36)), 604 ("content-encoding", "br") => Some(TableIndex::Field(42)), 605 ("content-encoding", "gzip") => Some(TableIndex::Field(43)), 606 ("content-encoding", _) => Some(TableIndex::FieldName(42)), 607 ("content-type", "application/dns-message") => Some(TableIndex::Field(44)), 608 ("content-type", "application/javascript") => Some(TableIndex::Field(45)), 609 ("content-type", "application/json") => Some(TableIndex::Field(46)), 610 ("content-type", "application/x-www-form-urlencoded") => { 611 Some(TableIndex::Field(47)) 612 } 613 ("content-type", "image/gif") => Some(TableIndex::Field(48)), 614 ("content-type", "image/jpeg") => Some(TableIndex::Field(49)), 615 ("content-type", "image/png") => Some(TableIndex::Field(50)), 616 ("content-type", "text/css") => Some(TableIndex::Field(51)), 617 ("content-type", "text/html; charset=utf-8") => Some(TableIndex::Field(52)), 618 ("content-type", "text/plain") => Some(TableIndex::Field(53)), 619 ("content-type", "text/plain;charset=utf-8") => Some(TableIndex::Field(54)), 620 ("content-type", _) => Some(TableIndex::FieldName(44)), 621 ("range", "bytes=0-") => Some(TableIndex::Field(55)), 622 ("range", _) => Some(TableIndex::FieldName(55)), 623 ("strict-transport-security", "max-age=31536000") => Some(TableIndex::Field(56)), 624 ("strict-transport-security", "max-age=31536000; includesubdomains") => { 625 Some(TableIndex::Field(57)) 626 } 627 ("strict-transport-security", "max-age=31536000; includesubdomains; preload") => { 628 Some(TableIndex::Field(58)) 629 } 630 ("strict-transport-security", _) => Some(TableIndex::FieldName(56)), 631 ("vary", "accept-encoding") => Some(TableIndex::Field(59)), 632 ("vary", "origin") => Some(TableIndex::Field(60)), 633 ("vary", _) => Some(TableIndex::FieldName(59)), 634 ("x-content-type-options", "nosniff") => Some(TableIndex::Field(61)), 635 ("x-content-type-options", _) => Some(TableIndex::FieldName(61)), 636 ("x-xss-protection", "1; mode=block") => Some(TableIndex::Field(62)), 637 ("x-xss-protection", _) => Some(TableIndex::FieldName(62)), 638 ("accept-language", _) => Some(TableIndex::FieldName(72)), 639 ("access-control-allow-credentials", "FALSE") => Some(TableIndex::Field(73)), 640 ("access-control-allow-credentials", "TRUE") => Some(TableIndex::Field(74)), 641 ("access-control-allow-credentials", _) => Some(TableIndex::FieldName(73)), 642 ("access-control-allow-headers", "*") => Some(TableIndex::Field(75)), 643 ("access-control-allow-headers", _) => Some(TableIndex::FieldName(75)), 644 ("access-control-allow-methods", "get") => Some(TableIndex::Field(76)), 645 ("access-control-allow-methods", "get, post, options") => { 646 Some(TableIndex::Field(77)) 647 } 648 ("access-control-allow-methods", "options") => Some(TableIndex::Field(78)), 649 ("access-control-allow-methods", _) => Some(TableIndex::FieldName(76)), 650 ("access-control-expose-headers", "content-length") => Some(TableIndex::Field(79)), 651 ("access-control-expose-headers", _) => Some(TableIndex::FieldName(79)), 652 ("access-control-request-headers", "content-type") => Some(TableIndex::Field(80)), 653 ("access-control-request-headers", _) => Some(TableIndex::FieldName(80)), 654 ("access-control-request-method", "get") => Some(TableIndex::Field(81)), 655 ("access-control-request-method", "post") => Some(TableIndex::Field(82)), 656 ("access-control-request-method", _) => Some(TableIndex::FieldName(81)), 657 ("alt-svc", "clear") => Some(TableIndex::Field(83)), 658 ("alt-svc", _) => Some(TableIndex::FieldName(83)), 659 ("authorization", _) => Some(TableIndex::FieldName(84)), 660 ( 661 "content-security-policy", 662 "script-src 'none'; object-src 'none'; base-uri 'none'", 663 ) => Some(TableIndex::Field(85)), 664 ("content-security-policy", _) => Some(TableIndex::FieldName(85)), 665 ("early-data", "1") => Some(TableIndex::Field(86)), 666 ("early-data", _) => Some(TableIndex::FieldName(86)), 667 ("expect-ct", _) => Some(TableIndex::FieldName(87)), 668 ("forwarded", _) => Some(TableIndex::FieldName(88)), 669 ("if-range", _) => Some(TableIndex::FieldName(89)), 670 ("origin", _) => Some(TableIndex::FieldName(90)), 671 ("purpose", "prefetch") => Some(TableIndex::Field(91)), 672 ("purpose", _) => Some(TableIndex::FieldName(91)), 673 ("server", _) => Some(TableIndex::FieldName(92)), 674 ("timing-allow-origin", "*") => Some(TableIndex::Field(93)), 675 ("timing-allow-origin", _) => Some(TableIndex::FieldName(93)), 676 ("upgrade-insecure-requests", "1") => Some(TableIndex::Field(94)), 677 ("upgrade-insecure-requests", _) => Some(TableIndex::FieldName(94)), 678 ("user-agent", _) => Some(TableIndex::FieldName(95)), 679 ("x-forwarded-for", _) => Some(TableIndex::FieldName(96)), 680 ("x-frame-options", "deny") => Some(TableIndex::Field(97)), 681 ("x-frame-options", "sameorigin") => Some(TableIndex::Field(98)), 682 ("x-frame-options", _) => Some(TableIndex::FieldName(97)), 683 _ => None, 684 }, 685 } 686 } 687 } 688 689 #[derive(Clone, PartialEq, Eq, Debug)] 690 pub enum Field { 691 Authority, 692 Method, 693 Path, 694 Scheme, 695 Status, 696 Other(String), 697 } 698 699 impl Field { len(&self) -> usize700 pub(crate) fn len(&self) -> usize { 701 match self { 702 Field::Authority => 10, // 10 is the length of ":authority". 703 Field::Method => 7, // 7 is the length of ":method". 704 Field::Path => 5, // 5 is the length of ":path". 705 Field::Scheme => 7, // 7 is the length of "scheme". 706 Field::Status => 7, // 7 is the length of "status". 707 Field::Other(s) => s.len(), 708 } 709 } 710 into_string(self) -> String711 pub(crate) fn into_string(self) -> String { 712 match self { 713 Field::Authority => String::from(":authority"), 714 Field::Method => String::from(":method"), 715 Field::Path => String::from(":path"), 716 Field::Scheme => String::from(":scheme"), 717 Field::Status => String::from(":status"), 718 Field::Other(s) => s, 719 } 720 } 721 } 722