|
1 | 1 | //! HTTP extensions.
|
2 | 2 |
|
3 | 3 | use bytes::Bytes;
|
| 4 | +use http::header::HeaderName; |
4 | 5 | #[cfg(feature = "http1")]
|
5 |
| -use http::header::{HeaderName, IntoHeaderName, ValueIter}; |
| 6 | +use http::header::{IntoHeaderName, ValueIter}; |
6 | 7 | use http::HeaderMap;
|
| 8 | +#[cfg(feature = "ffi")] |
| 9 | +use std::collections::HashMap; |
7 | 10 | #[cfg(feature = "http2")]
|
8 | 11 | use std::fmt;
|
9 | 12 |
|
@@ -120,3 +123,99 @@ impl HeaderCaseMap {
|
120 | 123 | self.0.append(name, orig);
|
121 | 124 | }
|
122 | 125 | }
|
| 126 | + |
| 127 | +#[cfg(feature = "ffi")] |
| 128 | +#[derive(Clone, Debug)] |
| 129 | +/// Hashmap<Headername, numheaders with that name> |
| 130 | +pub(crate) struct OriginalHeaderOrder { |
| 131 | + /// Stores how many entries a Headername maps to. This is used |
| 132 | + /// for accounting. |
| 133 | + num_entries: HashMap<HeaderName, usize>, |
| 134 | + /// Stores the ordering of the headers. ex: `vec[i] = (headerName, idx)`, |
| 135 | + /// The vector is ordered such that the ith element |
| 136 | + /// represents the ith header that came in off the line. |
| 137 | + /// The `HeaderName` and `idx` are then used elsewhere to index into |
| 138 | + /// the multi map that stores the header values. |
| 139 | + entry_order: Vec<(HeaderName, usize)>, |
| 140 | +} |
| 141 | + |
| 142 | +#[cfg(all(feature = "http1", feature = "ffi"))] |
| 143 | +impl OriginalHeaderOrder { |
| 144 | + pub(crate) fn default() -> Self { |
| 145 | + OriginalHeaderOrder { |
| 146 | + num_entries: HashMap::new(), |
| 147 | + entry_order: Vec::new(), |
| 148 | + } |
| 149 | + } |
| 150 | + |
| 151 | + pub(crate) fn insert(&mut self, name: HeaderName) { |
| 152 | + if !self.num_entries.contains_key(&name) { |
| 153 | + let idx = 0; |
| 154 | + self.num_entries.insert(name.clone(), 1); |
| 155 | + self.entry_order.push((name, idx)); |
| 156 | + } |
| 157 | + // Replacing an already existing element does not |
| 158 | + // change ordering, so we only care if its the first |
| 159 | + // header name encountered |
| 160 | + } |
| 161 | + |
| 162 | + pub(crate) fn append<N>(&mut self, name: N) |
| 163 | + where |
| 164 | + N: IntoHeaderName + Into<HeaderName> + Clone, |
| 165 | + { |
| 166 | + let name: HeaderName = name.into(); |
| 167 | + let idx; |
| 168 | + if self.num_entries.contains_key(&name) { |
| 169 | + idx = self.num_entries[&name]; |
| 170 | + *self.num_entries.get_mut(&name).unwrap() += 1; |
| 171 | + } else { |
| 172 | + idx = 0; |
| 173 | + self.num_entries.insert(name.clone(), 1); |
| 174 | + } |
| 175 | + self.entry_order.push((name, idx)); |
| 176 | + } |
| 177 | + |
| 178 | + // No doc test is run here because `RUSTFLAGS='--cfg hyper_unstable_ffi'` |
| 179 | + // is needed to compile. Once ffi is stablized `no_run` should be removed |
| 180 | + // here. |
| 181 | + /// This returns an iterator that provides header names and indexes |
| 182 | + /// in the original order recieved. |
| 183 | + /// |
| 184 | + /// # Examples |
| 185 | + /// ```no_run |
| 186 | + /// use hyper::ext::OriginalHeaderOrder; |
| 187 | + /// use hyper::header::{HeaderName, HeaderValue, HeaderMap}; |
| 188 | + /// |
| 189 | + /// let mut h_order = OriginalHeaderOrder::default(); |
| 190 | + /// let mut h_map = Headermap::new(); |
| 191 | + /// |
| 192 | + /// let name1 = b"Set-CookiE"; |
| 193 | + /// let value1 = b"a=b"; |
| 194 | + /// h_map.append(name1); |
| 195 | + /// h_order.append(name1); |
| 196 | + /// |
| 197 | + /// let name2 = b"Content-Encoding"; |
| 198 | + /// let value2 = b"gzip"; |
| 199 | + /// h_map.append(name2, value2); |
| 200 | + /// h_order.append(name2); |
| 201 | + /// |
| 202 | + /// let name3 = b"SET-COOKIE"; |
| 203 | + /// let value3 = b"c=d"; |
| 204 | + /// h_map.append(name3, value3); |
| 205 | + /// h_order.append(name3) |
| 206 | + /// |
| 207 | + /// let mut iter = h_order.get_in_order() |
| 208 | + /// |
| 209 | + /// let (name, idx) = iter.next(); |
| 210 | + /// assert_eq!(b"a=b", h_map.get_all(name).nth(idx).unwrap()); |
| 211 | + /// |
| 212 | + /// let (name, idx) = iter.next(); |
| 213 | + /// assert_eq!(b"gzip", h_map.get_all(name).nth(idx).unwrap()); |
| 214 | + /// |
| 215 | + /// let (name, idx) = iter.next(); |
| 216 | + /// assert_eq!(b"c=d", h_map.get_all(name).nth(idx).unwrap()); |
| 217 | + /// ``` |
| 218 | + pub(crate) fn get_in_order(&self) -> impl Iterator<Item = &(HeaderName, usize)> { |
| 219 | + self.entry_order.iter() |
| 220 | + } |
| 221 | +} |
0 commit comments