webview_bundle/
index.rs

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}