1use crate::checksum::{make_checksum, parse_checksum, write_checksum, CHECKSUM_LEN};
2use crate::header::Header;
3use crate::reader::Reader;
4use crate::writer::Writer;
5use bincode::de::Decoder;
6use bincode::enc::Encoder;
7use bincode::error::{DecodeError, EncodeError};
8use bincode::{config, decode_from_slice, encode_to_vec, Decode, Encode};
9use http::{HeaderMap, HeaderName, HeaderValue};
10use std::collections::HashMap;
11use std::io::{Read, Seek, SeekFrom, Write};
12use std::ops::{Deref, DerefMut};
13
14#[cfg(feature = "async")]
15use crate::reader::AsyncReader;
16#[cfg(feature = "async")]
17use crate::writer::AsyncWriter;
18#[cfg(feature = "async")]
19use tokio::io::{AsyncRead, AsyncReadExt, AsyncSeek, AsyncSeekExt, AsyncWrite, AsyncWriteExt};
20
21#[derive(Debug, PartialEq, Clone)]
22pub struct IndexEntry {
23 offset: u64,
24 len: u64,
25 pub(crate) headers: HeaderMap,
26}
27
28impl IndexEntry {
29 pub fn new(offset: u64, len: u64) -> Self {
30 Self {
31 offset,
32 len,
33 headers: HeaderMap::default(),
34 }
35 }
36
37 pub fn headers(&self) -> &HeaderMap {
38 &self.headers
39 }
40
41 pub fn offset(&self) -> u64 {
42 self.offset
43 }
44
45 pub fn is_empty(&self) -> bool {
46 self.len == 0
47 }
48
49 pub fn len(&self) -> u64 {
50 self.len
51 }
52}
53
54impl Encode for IndexEntry {
55 fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
56 let mut pairs: Vec<(String, Vec<u8>)> = Vec::with_capacity(self.headers.len());
57 for (name, value) in self.headers.iter() {
58 pairs.push((name.as_str().to_string(), value.as_bytes().to_vec()));
59 }
60 let tuple = (self.offset, self.len, pairs);
61 tuple.encode(encoder)?;
62 Ok(())
63 }
64}
65
66impl<T> Decode<T> for IndexEntry {
67 fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
68 let (offset, len, pairs): (u64, u64, Vec<(String, Vec<u8>)>) = Decode::decode(decoder)?;
69 let mut headers = HeaderMap::new();
70 for (name, value_bytes) in pairs {
71 let header_name = HeaderName::try_from(name.as_str())
72 .map_err(|_| DecodeError::OtherString("invalid header name".into()))?;
73 let header_value = HeaderValue::from_bytes(&value_bytes)
74 .map_err(|_| DecodeError::OtherString("invalid header value".into()))?;
75 headers.append(header_name, header_value);
76 }
77 Ok(IndexEntry {
78 offset,
79 len,
80 headers,
81 })
82 }
83}
84
85#[derive(Debug, Default, PartialEq, Clone)]
86pub(crate) struct IndexEntryMap(pub(crate) HashMap<String, IndexEntry>);
87
88#[derive(Debug, Default, PartialEq, Clone)]
89pub struct Index {
90 entries: IndexEntryMap,
91}
92
93impl Index {
94 pub fn new() -> Self {
95 Self::default()
96 }
97
98 pub fn new_with_capacity(capacity: usize) -> Self {
99 Self {
100 entries: IndexEntryMap(HashMap::with_capacity(capacity)),
101 }
102 }
103}
104
105impl Encode for IndexEntryMap {
106 fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
107 self.0.encode(encoder)
108 }
109}
110
111impl<T> Decode<T> for IndexEntryMap {
112 fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
113 let map = HashMap::<String, IndexEntry>::decode(decoder)?;
114 Ok(IndexEntryMap(map))
115 }
116}
117
118impl Deref for IndexEntryMap {
119 type Target = HashMap<String, IndexEntry>;
120 fn deref(&self) -> &Self::Target {
121 &self.0
122 }
123}
124
125impl DerefMut for IndexEntryMap {
126 fn deref_mut(&mut self) -> &mut Self::Target {
127 &mut self.0
128 }
129}
130
131impl Index {
132 pub fn entries(&self) -> &HashMap<String, IndexEntry> {
133 &self.entries
134 }
135
136 pub fn insert_entry<S: Into<String>>(
137 &mut self,
138 path: S,
139 entry: IndexEntry,
140 ) -> Option<IndexEntry> {
141 self.entries.insert(path.into(), entry)
142 }
143
144 pub fn get_entry(&self, path: &str) -> Option<&IndexEntry> {
145 self.entries.get(path)
146 }
147
148 pub fn get_entry_mut(&mut self, path: &str) -> Option<&mut IndexEntry> {
149 self.entries.get_mut(path)
150 }
151
152 pub fn remove_entry(&mut self, path: &str) -> Option<IndexEntry> {
153 self.entries.remove(path)
154 }
155
156 pub fn contains_path(&self, path: &str) -> bool {
157 self.entries.contains_key(path)
158 }
159}
160
161fn write_index(index: &Index) -> crate::Result<Vec<u8>> {
162 let config = config::standard().with_big_endian();
163 let bytes = encode_to_vec(&index.entries, config).map_err(|e| crate::Error::Encode {
164 error: e,
165 message: "fail to encode index".to_string(),
166 })?;
167 Ok(bytes)
168}
169
170#[derive(Debug, Default, Clone, Copy, PartialEq)]
171pub struct IndexWriterOptions {
172 pub(crate) checksum_seed: u32,
173}
174
175impl IndexWriterOptions {
176 pub fn new() -> Self {
177 Self::default()
178 }
179
180 pub fn checksum_seed(&mut self, seed: u32) -> &mut Self {
181 self.checksum_seed = seed;
182 self
183 }
184}
185
186pub struct IndexWriter<W: Write> {
187 w: W,
188 options: IndexWriterOptions,
189}
190
191impl<W: Write> IndexWriter<W> {
192 pub fn new(w: W) -> Self {
193 Self {
194 w,
195 options: Default::default(),
196 }
197 }
198
199 pub fn new_with_options(w: W, options: IndexWriterOptions) -> Self {
200 Self { w, options }
201 }
202
203 pub fn write_index(&mut self, index: &Index) -> crate::Result<Vec<u8>> {
204 let bytes = write_index(index)?;
205 self.w.write_all(&bytes)?;
206 Ok(bytes)
207 }
208
209 pub fn write_checksum(&mut self, checksum: u32) -> crate::Result<Vec<u8>> {
210 let bytes = write_checksum(checksum);
211 self.w.write_all(&bytes)?;
212 Ok(bytes)
213 }
214}
215
216impl<W: Write> Writer<Index> for IndexWriter<W> {
217 fn write(&mut self, index: &Index) -> crate::Result<usize> {
218 let mut bytes = vec![];
219 bytes.extend(self.write_index(index)?);
220 let checksum = make_checksum(self.options.checksum_seed, &bytes);
221 bytes.extend(self.write_checksum(checksum)?);
222 Ok(bytes.len())
223 }
224}
225
226#[cfg(feature = "async")]
227pub struct AsyncIndexWriter<W: AsyncWrite + Unpin> {
228 w: W,
229 options: IndexWriterOptions,
230}
231
232#[cfg(feature = "async")]
233impl<W: AsyncWrite + Unpin> AsyncIndexWriter<W> {
234 pub fn new(w: W) -> Self {
235 Self {
236 w,
237 options: Default::default(),
238 }
239 }
240
241 pub fn new_with_options(w: W, options: IndexWriterOptions) -> Self {
242 Self { w, options }
243 }
244
245 pub async fn write_index(&mut self, index: &Index) -> crate::Result<Vec<u8>> {
246 let bytes = write_index(index)?;
247 self.w.write_all(&bytes).await?;
248 Ok(bytes)
249 }
250
251 pub async fn write_checksum(&mut self, checksum: u32) -> crate::Result<Vec<u8>> {
252 let bytes = write_checksum(checksum);
253 self.w.write_all(&bytes).await?;
254 Ok(bytes)
255 }
256}
257
258#[cfg(feature = "async")]
259impl<W: AsyncWrite + Unpin> AsyncWriter<Index> for AsyncIndexWriter<W> {
260 async fn write(&mut self, index: &Index) -> crate::Result<usize> {
261 let mut bytes = vec![];
262 bytes.extend(self.write_index(index).await?);
263 let checksum = make_checksum(self.options.checksum_seed, &bytes);
264 bytes.extend(self.write_checksum(checksum).await?);
265 Ok(bytes.len())
266 }
267}
268
269fn read_index(header: &Header) -> (u64, Vec<u8>) {
270 (Header::END_OFFSET, vec![0u8; header.index_size() as usize])
271}
272
273fn parse_index(buf: &[u8]) -> crate::Result<Index> {
274 let config = config::standard().with_big_endian();
275 let (entries, _): (IndexEntryMap, _) =
276 decode_from_slice(buf, config).map_err(|e| crate::Error::Decode {
277 error: e,
278 message: "fail to decode index".to_string(),
279 })?;
280 Ok(Index { entries })
281}
282
283fn read_checksum(header: &Header) -> (u64, [u8; CHECKSUM_LEN]) {
284 (
285 Header::END_OFFSET + header.index_size() as u64,
286 [0u8; CHECKSUM_LEN],
287 )
288}
289
290fn read_total(header: &Header) -> (u64, Vec<u8>) {
291 (Header::END_OFFSET, vec![0u8; header.index_size() as usize])
292}
293
294pub struct IndexReader<R: Read + Seek> {
295 r: R,
296 header: Header,
297 options: IndexReaderOptions,
298}
299
300#[derive(Debug, Default, Clone, Copy, PartialEq)]
301pub struct IndexReaderOptions {
302 pub checksum_seed: u32,
303 pub verify_checksum: bool,
304}
305
306impl IndexReaderOptions {
307 pub fn new() -> Self {
308 Self::default()
309 }
310
311 pub fn checksum_seed(mut self, seed: u32) -> Self {
312 self.checksum_seed = seed;
313 self
314 }
315
316 pub fn verify_checksum(mut self, verify: bool) -> Self {
317 self.verify_checksum = verify;
318 self
319 }
320}
321
322impl<R: Read + Seek> IndexReader<R> {
323 pub fn new(r: R, header: Header) -> Self {
324 Self::new_with_options(r, header, Default::default())
325 }
326
327 pub fn new_with_options(r: R, header: Header, options: IndexReaderOptions) -> Self {
328 Self { r, header, options }
329 }
330
331 pub fn read_index(&mut self) -> crate::Result<Index> {
332 let (offset, mut buf) = read_index(&self.header);
333 self.r.seek(SeekFrom::Start(offset))?;
334 self.r.read_exact(&mut buf)?;
335 parse_index(&buf)
336 }
337
338 pub fn read_checksum(&mut self) -> crate::Result<u32> {
339 let (offset, mut buf) = read_checksum(&self.header);
340 self.r.seek(SeekFrom::Start(offset))?;
341 self.r.read_exact(&mut buf)?;
342 let checksum = parse_checksum(&buf);
343 Ok(checksum)
344 }
345
346 fn verify_checksum(&mut self, checksum: u32) -> crate::Result<()> {
347 let (offset, mut buf) = read_total(&self.header);
348 self.r.seek(SeekFrom::Start(offset))?;
349 self.r.read_exact(&mut buf)?;
350
351 let expected_checksum = make_checksum(self.options.checksum_seed, &buf);
352 if checksum != expected_checksum {
353 return Err(crate::Error::InvalidIndexChecksum);
354 }
355 Ok(())
356 }
357}
358
359impl<R: Read + Seek> Reader<Index> for IndexReader<R> {
360 fn read(&mut self) -> crate::Result<Index> {
361 let index = self.read_index()?;
362 let checksum = self.read_checksum()?;
363 if self.options.verify_checksum {
364 self.verify_checksum(checksum)?;
365 }
366 Ok(index)
367 }
368}
369
370#[cfg(feature = "async")]
371pub struct AsyncIndexReader<R: AsyncRead + AsyncSeek + Unpin> {
372 r: R,
373 header: Header,
374 options: IndexReaderOptions,
375}
376
377#[cfg(feature = "async")]
378impl<R: AsyncRead + AsyncSeek + Unpin> AsyncIndexReader<R> {
379 pub fn new(r: R, header: Header) -> Self {
380 Self::new_with_options(r, header, Default::default())
381 }
382
383 pub fn new_with_options(r: R, header: Header, options: IndexReaderOptions) -> Self {
384 Self { r, header, options }
385 }
386
387 pub async fn read_index(&mut self) -> crate::Result<Index> {
388 let (offset, mut buf) = read_index(&self.header);
389 self.r.seek(SeekFrom::Start(offset)).await?;
390 self.r.read_exact(&mut buf).await?;
391 parse_index(&buf)
392 }
393
394 pub async fn read_checksum(&mut self) -> crate::Result<u32> {
395 let (offset, mut buf) = read_checksum(&self.header);
396 self.r.seek(SeekFrom::Start(offset)).await?;
397 self.r.read_exact(&mut buf).await?;
398 let checksum = parse_checksum(&buf);
399 Ok(checksum)
400 }
401
402 async fn verify_checksum(&mut self, checksum: u32) -> crate::Result<()> {
403 let (offset, mut buf) = read_total(&self.header);
404 self.r.seek(SeekFrom::Start(offset)).await?;
405 self.r.read_exact(&mut buf).await?;
406
407 let expected_checksum = make_checksum(self.options.checksum_seed, &buf);
408 if checksum != expected_checksum {
409 return Err(crate::Error::InvalidIndexChecksum);
410 }
411 Ok(())
412 }
413}
414
415#[cfg(feature = "async")]
416impl<R: AsyncRead + AsyncSeek + Unpin> AsyncReader<Index> for AsyncIndexReader<R> {
417 async fn read(&mut self) -> crate::Result<Index> {
418 let index = self.read_index().await?;
419 let checksum = self.read_checksum().await?;
420 if self.options.verify_checksum {
421 self.verify_checksum(checksum).await?;
422 }
423 Ok(index)
424 }
425}
426
427#[cfg(test)]
428mod tests {
429 use super::*;
430
431 #[test]
432 fn index() {
433 let mut index = Index::default();
434 let mut entry = IndexEntry::new(0, 0);
435 entry.headers.append(
436 HeaderName::from_static("content-type"),
437 HeaderValue::from_static("application/javascript"),
438 );
439 index.insert_entry("/index.jsx", entry);
440
441 assert!(index.contains_path("/index.jsx"));
442 assert_eq!(
443 index
444 .get_entry("/index.jsx")
445 .map(|x| x.headers.get("content-type"))
446 .unwrap(),
447 Some(&HeaderValue::from_static("application/javascript"))
448 );
449 }
450
451 #[cfg(feature = "async")]
452 #[tokio::test]
453 async fn async_read_and_write() {
454 use crate::HeaderWriter;
455 use crate::Version;
456 use std::io::Cursor;
457
458 let mut index = Index::default();
459 let mut entry = IndexEntry::new(0, 0);
460 entry.headers.append(
461 HeaderName::from_static("content-type"),
462 HeaderValue::from_static("application/javascript"),
463 );
464 index.insert_entry("/index.jsx", entry);
465
466 let mut buf = vec![];
467 let mut writer = AsyncIndexWriter::new(Cursor::new(&mut buf));
468 writer.write(&index).await.unwrap();
469 assert_eq!(
470 buf,
471 vec![
472 1, 10, 47, 105, 110, 100, 101, 120, 46, 106, 115, 120, 0, 0, 1, 12, 99, 111, 110, 116, 101,
473 110, 116, 45, 116, 121, 112, 101, 22, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110,
474 47, 106, 97, 118, 97, 115, 99, 114, 105, 112, 116, 49, 24, 219, 15
475 ]
476 );
477 let header = Header::new(Version::V1, (buf.len() - CHECKSUM_LEN) as u32);
478 let mut total = vec![];
479 HeaderWriter::new(Cursor::new(&mut total))
480 .write(&header)
481 .unwrap();
482 total.extend(&buf);
483 let mut reader = AsyncIndexReader::new(Cursor::new(&total), header);
484 let read_index = reader.read().await.unwrap();
485 assert_eq!(read_index, index);
486 }
487}