1#![warn(rust_2018_idioms)]
41
42use std::error::Error as StdError;
43use std::env;
44use std::fmt;
45use std::fs::File;
46use std::io;
47use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
48use std::mem;
49use std::path::Path;
50use std::sync::Arc;
51
52use bytes::{Bytes, BytesMut, BufMut};
53
54use tao_log::{debug, warn};
55use olio::io::GatheringReader;
56use olio::fs::rc::{ReadPos, ReadSlice};
57use tempfile::tempfile_in;
58
59#[cfg(feature = "mmap")] #[doc(hidden)] pub mod _mem_handle_ext;
60
61#[cfg(feature = "mmap")]
62use {
63 memmap::Mmap,
64 olio::mem::{MemAdvice, MemHandle},
65 _mem_handle_ext::MemHandleExt,
66};
67
68pub static VERSION: &str = env!("CARGO_PKG_VERSION");
70
71#[derive(Debug)]
76pub enum BodyError {
77 BodyTooLong(u64),
79
80 Io(io::Error),
83
84 _FutureProof
87}
88
89impl fmt::Display for BodyError {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 match *self {
92 BodyError::BodyTooLong(l) =>
93 write!(
94 f, "Body length of {}+ bytes exceeds Tunables::max_body",
95 l
96 ),
97 BodyError::Io(ref e) =>
98 write!(f, "Body I/O: {}", e),
99 BodyError::_FutureProof =>
100 unreachable!("Don't abuse the _FutureProof!")
101 }
102 }
103}
104
105impl StdError for BodyError {
106 fn source(&self) -> Option<&(dyn StdError + 'static)> {
107 match *self {
108 BodyError::Io(ref e) => Some(e),
109 _ => None
110 }
111 }
112}
113
114impl From<io::Error> for BodyError {
115 fn from(err: io::Error) -> BodyError {
116 BodyError::Io(err)
117 }
118}
119
120#[derive(Clone, Debug)]
145pub struct BodyImage {
146 state: ImageState,
147 len: u64
148}
149
150#[derive(Clone)]
152enum ImageState {
153 Ram(Vec<Bytes>),
154 FsRead(Arc<File>),
155 FsReadSlice(ReadSlice),
156 #[cfg(feature = "mmap")]
157 MemMap(MemHandle<Mmap>),
158}
159
160#[derive(Debug)]
175pub struct BodySink {
176 state: SinkState,
177 len: u64
178}
179
180enum SinkState {
181 Ram(Vec<Bytes>),
182 FsWrite(File),
183}
184
185impl SinkState {
186 fn cut(&mut self) -> Self {
189 mem::replace(self, SinkState::Ram(Vec::with_capacity(0)))
190 }
191}
192
193impl BodySink {
194 pub fn empty() -> BodySink {
197 BodySink::with_ram_buffers(0)
198 }
199
200 pub fn with_ram(size_estimate: u64) -> BodySink {
204 if size_estimate == 0 {
205 BodySink::empty()
206 } else {
207 let cap = (size_estimate / 0x2000 + 1) as usize;
209 BodySink::with_ram_buffers(cap)
210 }
211 }
212
213 pub fn with_ram_buffers(capacity: usize) -> BodySink {
216 BodySink {
217 state: SinkState::Ram(Vec::with_capacity(capacity)),
218 len: 0
219 }
220 }
221
222 pub fn with_fs<P>(dir: P) -> Result<BodySink, BodyError>
225 where P: AsRef<Path>
226 {
227 let f = tempfile_in(dir)?;
228 Ok(BodySink {
229 state: SinkState::FsWrite(f),
230 len: 0
231 })
232 }
233
234 pub fn is_ram(&self) -> bool {
236 match self.state {
237 SinkState::Ram(_) => true,
238 _ => false
239 }
240 }
241
242 pub fn is_empty(&self) -> bool {
244 self.len == 0
245 }
246
247 pub fn len(&self) -> u64 {
249 self.len
250 }
251
252 #[deprecated(since="2.0.0", note="use `push` or `write_all` instead")]
255 #[inline]
256 pub fn save<T>(&mut self, buf: T) -> Result<(), BodyError>
257 where T: Into<Bytes>
258 {
259 let buf = buf.into();
260 self.push(buf).map_err(BodyError::from)
261 }
262
263 pub fn push<T>(&mut self, buf: T) -> Result<(), io::Error>
270 where T: Into<Bytes> + AsRef<[u8]>
271 {
272 match self.state {
273 SinkState::Ram(ref mut v) => {
274 let buf = buf.into();
275 let len = buf.len() as u64;
276 if len > 0 {
277 v.push(buf);
278 self.len += len;
279 }
280 }
281 SinkState::FsWrite(ref mut f) => {
282 let buf = buf.as_ref();
283 let len = buf.len() as u64;
284 if len > 0 {
285 f.write_all(buf)?;
286 self.len += len;
287 }
288 }
289 }
290 Ok(())
291 }
292
293 pub fn write_all<T>(&mut self, buf: T) -> Result<(), io::Error>
298 where T: AsRef<[u8]>
299 {
300 let buf = buf.as_ref();
301 let len = buf.len() as u64;
302 if len > 0 {
303 match self.state {
304 SinkState::Ram(ref mut v) => {
305 v.push(Bytes::copy_from_slice(buf));
306 }
307 SinkState::FsWrite(ref mut f) => {
308 f.write_all(buf)?;
309 }
310 }
311 self.len += len;
312 }
313 Ok(())
314 }
315
316 pub fn write_back<P>(&mut self, dir: P) -> Result<&mut Self, BodyError>
323 where P: AsRef<Path>
324 {
325 if self.is_ram() {
326 if let SinkState::Ram(v) = self.state.cut() {
327 let olen = self.len;
328 self.len = 0;
329 let mut f = tempfile_in(dir)?;
330 for b in v {
331 f.write_all(&b)?;
332 drop::<Bytes>(b); }
334 self.state = SinkState::FsWrite(f);
335 self.len = olen;
336 }
337 }
338 Ok(self)
339 }
340
341 pub fn prepare(self) -> Result<BodyImage, BodyError> {
343 match self.state {
344 SinkState::Ram(v) => {
345 Ok(BodyImage {
346 state: ImageState::Ram(v),
347 len: self.len
348 })
349 }
350 SinkState::FsWrite(mut f) => {
351 if self.len == 0 {
354 Ok(BodyImage::empty())
355 } else {
356 f.flush()?;
357 f.seek(SeekFrom::Start(0))?;
358 Ok(BodyImage {
359 state: ImageState::FsRead(Arc::new(f)),
360 len: self.len
361 })
362 }
363 }
364 }
365 }
366}
367
368impl Default for BodySink {
369 fn default() -> BodySink { BodySink::empty() }
370}
371
372impl fmt::Debug for SinkState {
373 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374 match *self {
375 SinkState::Ram(ref v) => {
376 f.debug_struct("Ram(Vec<Bytes>)")
378 .field("capacity", &v.capacity())
379 .field("len", &v.len())
380 .finish()
381 }
382 SinkState::FsWrite(ref file) => {
383 f.debug_tuple("FsWrite")
384 .field(file)
385 .finish()
386 }
387 }
388 }
389}
390
391impl ImageState {
392 fn empty() -> ImageState {
393 ImageState::Ram(Vec::with_capacity(0))
394 }
395
396 fn cut(&mut self) -> Self {
399 mem::replace(self, ImageState::empty())
400 }
401}
402
403impl BodyImage {
404 pub fn empty() -> BodyImage {
407 BodyImage {
408 state: ImageState::empty(),
409 len: 0
410 }
411 }
412
413 #[cfg(feature = "mmap")]
431 pub unsafe fn from_file(file: File, length: u64) -> BodyImage {
432 image_from_file(file, length)
433 }
434
435 #[cfg(not(feature = "mmap"))]
442 pub fn from_file(file: File, length: u64) -> BodyImage {
443 image_from_file(file, length)
444 }
445
446 pub fn from_slice<T>(bytes: T) -> BodyImage
448 where T: Into<Bytes>
449 {
450 let mut bs = BodySink::with_ram_buffers(1);
451 let buf = bytes.into();
452 bs.push(buf).expect("push is safe to Ram");
453 bs.prepare().expect("prepare is safe to Ram")
454 }
455
456 #[cfg(feature = "mmap")]
473 pub unsafe fn from_read_slice(rslice: ReadSlice) -> BodyImage {
474 image_from_read_slice(rslice)
475 }
476
477 #[cfg(not(feature = "mmap"))]
483 pub fn from_read_slice(rslice: ReadSlice) -> BodyImage {
484 image_from_read_slice(rslice)
485 }
486
487 pub fn is_ram(&self) -> bool {
489 match self.state {
490 ImageState::Ram(_) => true,
491 _ => false
492 }
493 }
494
495 #[cfg(feature = "mmap")]
497 pub fn is_mem_map(&self) -> bool {
498 match self.state {
499 ImageState::MemMap(_) => true,
500 _ => false
501 }
502 }
503
504 pub fn len(&self) -> u64 {
506 self.len
507 }
508
509 pub fn is_empty(&self) -> bool {
511 self.len == 0
512 }
513
514 #[cfg(feature = "mmap")]
521 pub fn mem_map(&mut self) -> Result<&mut Self, BodyError> {
522 let map = match self.state {
523 ImageState::FsRead(ref file) => {
524 assert!(self.len > 0);
525 unsafe { Mmap::map(&file) }?
526 }
527 ImageState::FsReadSlice(ref rslice) => {
528 rslice.mem_map()?
529 }
530 _ => return Ok(self)
531 };
532
533 self.state = ImageState::MemMap(MemHandle::new(map));
534 Ok(self)
535 }
536
537 pub fn gather(&mut self) -> &mut Self {
543 let scattered = if let ImageState::Ram(ref v) = self.state {
544 v.len() > 1
545 } else {
546 false
547 };
548
549 if scattered {
550 if let ImageState::Ram(v) = self.state.cut() {
551 let mut newb = BytesMut::with_capacity(self.len as usize);
552 for b in v {
553 newb.put_slice(&b);
554 drop::<Bytes>(b); }
556 let newb = newb.freeze();
557 assert_eq!(newb.len() as u64, self.len);
558 self.state = ImageState::Ram(vec![newb]);
559 }
560 }
561 self
562 }
563
564 pub fn reader(&self) -> BodyReader<'_> {
568 match self.state {
569 ImageState::Ram(ref v) => {
570 if v.is_empty() {
571 BodyReader::Contiguous(Cursor::new(&[]))
572 } else if v.len() == 1 {
573 BodyReader::Contiguous(Cursor::new(&v[0]))
574 } else {
575 BodyReader::Scattered(GatheringReader::new(v))
576 }
577 }
578 ImageState::FsRead(ref f) => {
579 BodyReader::FileSlice(ReadSlice::new(f.clone(), 0, self.len))
580 }
581 ImageState::FsReadSlice(ref rslice) => {
582 BodyReader::FileSlice(rslice.clone())
583 }
584 #[cfg(feature = "mmap")]
585 ImageState::MemMap(ref m) => {
586 BodyReader::Contiguous(Cursor::new(m))
587 }
588 }
589 }
590
591 pub fn explode(self) -> ExplodedImage {
593 match self.state {
594 ImageState::Ram(v) => ExplodedImage::Ram(v),
595 ImageState::FsRead(f) => {
596 ExplodedImage::FsRead(ReadSlice::new(f, 0, self.len))
597 }
598 ImageState::FsReadSlice(rs) => ExplodedImage::FsRead(rs),
599 #[cfg(feature = "mmap")]
600 ImageState::MemMap(m) => ExplodedImage::MemMap(m),
601 }
602 }
603
604 pub fn read_from<R>(rin: &mut R, len_estimate: u64, tune: &Tunables)
617 -> Result<BodyImage, BodyError>
618 where R: Read + ?Sized
619 {
620 if len_estimate > tune.max_body_ram() {
621 let b = BodySink::with_fs(tune.temp_dir())?;
622 return read_to_body_fs(rin, b, tune);
623 }
624
625 let mut body = BodySink::with_ram(len_estimate);
626
627 let mut size: u64 = 0;
628 'eof: loop {
629 let mut buf = BytesMut::with_capacity(tune.buffer_size_ram());
630 'fill: loop {
631 let b = unsafe { &mut *(
632 buf.chunk_mut() as *mut _
633 as *mut [mem::MaybeUninit<u8>]
634 as *mut [u8]
635 )};
636 let len = match rin.read(b) {
637 Ok(len) => len,
638 Err(e) => {
639 if e.kind() == ErrorKind::Interrupted {
640 continue;
641 } else {
642 return Err(e.into());
643 }
644 }
645 };
646 if len == 0 {
647 break 'fill; }
650 unsafe { buf.advance_mut(len); }
651
652 if buf.remaining_mut() < 1024 {
653 break 'fill;
654 }
655 }
656 let len = buf.len() as u64;
657 if len == 0 {
658 break 'eof;
659 }
660 size += len;
661 if size > tune.max_body() {
662 return Err(BodyError::BodyTooLong(size));
663 }
664 if size > tune.max_body_ram() {
665 body.write_back(tune.temp_dir())?;
666 debug!("Write (Fs) buffer len {}", len);
667 body.write_all(&buf)?;
668 return read_to_body_fs(rin, body, tune)
669 }
670 debug!("Saved (Ram) buffer len {}", len);
671 body.push(buf.freeze())?;
672 }
673 let body = body.prepare()?;
674 Ok(body)
675 }
676
677 pub fn write_to<W>(&self, out: &mut W) -> Result<u64, BodyError>
688 where W: Write + ?Sized
689 {
690 match self.state {
691 ImageState::Ram(ref v) => {
692 for b in v {
693 out.write_all(b)?;
694 }
695 }
696 #[cfg(feature = "mmap")]
697 ImageState::MemMap(ref mh) => {
698 mh.tmp_advise(MemAdvice::Sequential, || out.write_all(mh))?;
699 }
700 ImageState::FsRead(ref f) => {
701 let mut rp = ReadPos::new(f.clone(), self.len);
702 io::copy(&mut rp, out)?;
703 }
704 ImageState::FsReadSlice(ref rslice) => {
705 let mut rs = rslice.clone();
706 io::copy(&mut rs, out)?;
707 }
708 }
709 Ok(self.len)
710 }
711}
712
713fn image_from_file(file: File, length: u64) -> BodyImage {
715 if length > 0 {
716 BodyImage {
717 state: ImageState::FsRead(Arc::new(file)),
718 len: length
719 }
720 } else {
721 BodyImage::empty()
722 }
723}
724
725fn image_from_read_slice(rslice: ReadSlice) -> BodyImage {
727 let len = rslice.len();
728 if len > 0 {
729 BodyImage { state: ImageState::FsReadSlice(rslice), len }
730 } else {
731 BodyImage::empty()
732 }
733}
734
735fn read_to_body_fs<R>(r: &mut R, mut body: BodySink, tune: &Tunables)
738 -> Result<BodyImage, BodyError>
739 where R: Read + ?Sized
740{
741 assert!(!body.is_ram());
742
743 let mut size: u64 = 0;
744 let mut buf = BytesMut::with_capacity(tune.buffer_size_fs());
745 loop {
746 let b = unsafe { &mut *(
747 buf.chunk_mut() as *mut _
748 as *mut [mem::MaybeUninit<u8>]
749 as *mut [u8]
750 )};
751 let len = match r.read(b) {
752 Ok(l) => l,
753 Err(e) => {
754 if e.kind() == ErrorKind::Interrupted {
755 continue;
756 } else {
757 return Err(e.into());
758 }
759 }
760 };
761 if len == 0 {
762 break;
763 }
764 unsafe { buf.advance_mut(len); }
765
766 size += len as u64;
767 if size > tune.max_body() {
768 return Err(BodyError::BodyTooLong(size));
769 }
770 debug!("Write (Fs) buffer len {}", len);
771 body.write_all(&buf)?;
772 buf.clear();
773 }
774 let body = body.prepare()?;
775 Ok(body)
776}
777
778impl Default for BodyImage {
779 fn default() -> BodyImage { BodyImage::empty() }
780}
781
782impl fmt::Debug for ImageState {
783 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
784 match *self {
785 ImageState::Ram(ref v) => {
786 f.debug_struct("Ram(Vec<Bytes>)")
788 .field("capacity", &v.capacity())
789 .field("len", &v.len())
790 .finish()
791 }
792 ImageState::FsRead(ref file) => {
793 f.debug_tuple("FsRead")
794 .field(file)
795 .finish()
796 }
797 ImageState::FsReadSlice(ref rslice) => {
798 f.debug_tuple("FsReadSlice")
799 .field(rslice)
800 .finish()
801 }
802 #[cfg(feature = "mmap")]
803 ImageState::MemMap(ref m) => {
804 f.debug_tuple("MemMap")
805 .field(m)
806 .finish()
807 }
808 }
809 }
810}
811
812pub enum ExplodedImage {
815 Ram(Vec<Bytes>),
816 FsRead(ReadSlice),
817 #[cfg(feature = "mmap")]
818 MemMap(MemHandle<Mmap>),
819}
820
821pub enum BodyReader<'a> {
823 Contiguous(Cursor<&'a [u8]>),
827
828 Scattered(GatheringReader<'a, Bytes>),
831
832 FileSlice(ReadSlice),
837}
838
839impl<'a> Read for BodyReader<'a> {
840 #[inline]
841 fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
842 match *self {
843 BodyReader::Contiguous(ref mut cursor) => cursor.read(buf),
844 BodyReader::Scattered(ref mut gatherer) => gatherer.read(buf),
845 BodyReader::FileSlice(ref mut rslice) => rslice.read(buf),
846 }
847 }
848}
849
850#[derive(Clone, Debug)]
854pub struct Prolog {
855 pub method: http::Method,
856 pub url: http::Uri,
857 pub req_headers: http::HeaderMap,
858 pub req_body: BodyImage,
859}
860
861#[derive(Clone, Debug)]
863pub struct Epilog {
864 pub version: http::Version,
865 pub status: http::StatusCode,
866 pub res_headers: http::HeaderMap,
867 pub res_body: BodyImage,
868 pub res_decoded: Vec<Encoding>,
869}
870
871#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
875pub enum Encoding {
876 Chunked,
879 Deflate,
880 Gzip,
881 Brotli,
882 Compress,
885 Identity,
888}
889
890impl fmt::Display for Encoding {
891 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
892 f.write_str(match *self {
893 Encoding::Chunked => "chunked",
894 Encoding::Deflate => "deflate",
895 Encoding::Gzip => "gzip",
896 Encoding::Brotli => "br",
897 Encoding::Compress => "compress",
898 Encoding::Identity => "identity",
899 })
900 }
901}
902
903#[derive(Clone, Debug)]
913pub struct Dialog {
914 pro: Prolog,
915 epi: Epilog,
916}
917
918pub trait RequestRecorded {
920 fn req_headers(&self) -> &http::HeaderMap;
922
923 fn req_body(&self) -> &BodyImage;
926}
927
928pub trait Recorded: RequestRecorded {
931 fn res_headers(&self) -> &http::HeaderMap;
933
934 fn res_body(&self) -> &BodyImage;
936}
937
938impl Dialog {
939 pub fn new(pro: Prolog, epi: Epilog) -> Dialog {
941 Dialog { pro, epi }
942 }
943
944 pub fn method(&self) -> &http::Method { &self.pro.method }
946
947 pub fn url(&self) -> &http::Uri { &self.pro.url }
949
950 pub fn req_body_mut(&mut self) -> &mut BodyImage {
953 &mut self.pro.req_body
954 }
955
956 pub fn res_status(&self) -> http::StatusCode { self.epi.status }
958
959 pub fn res_version(&self) -> http::Version { self.epi.version }
961
962 pub fn res_decoded(&self) -> &Vec<Encoding> { &self.epi.res_decoded }
965
966 pub fn set_res_decoded(&mut self, decoded: Vec<Encoding>) {
968 self.epi.res_decoded = decoded;
969 }
970
971 pub fn res_body_mut(&mut self) -> &mut BodyImage { &mut self.epi.res_body }
974
975 pub fn set_res_body_decoded(&mut self, body: BodyImage, decoded: Vec<Encoding>) {
977 self.epi.res_body = body;
978 self.epi.res_decoded = decoded;
979 }
980
981 pub fn explode(self) -> (Prolog, Epilog) {
984 (self.pro, self.epi)
985 }
986}
987
988impl RequestRecorded for Dialog {
989 fn req_headers(&self) -> &http::HeaderMap { &self.pro.req_headers }
990 fn req_body(&self) -> &BodyImage { &self.pro.req_body }
991}
992
993impl Recorded for Dialog {
994 fn res_headers(&self) -> &http::HeaderMap { &self.epi.res_headers }
995 fn res_body(&self) -> &BodyImage { &self.epi.res_body }
996}
997
998#[derive(Debug, Clone)]
1001pub struct Tunables {
1002 max_body_ram: u64,
1003 max_body: u64,
1004 buffer_size_ram: usize,
1005 buffer_size_fs: usize,
1006 size_estimate_deflate: u16,
1007 size_estimate_gzip: u16,
1008 size_estimate_brotli: u16,
1009 temp_dir: Arc<Path>,
1010}
1011
1012impl Tunables {
1013 pub fn new() -> Tunables {
1015 Tunables {
1016 max_body_ram: 192 * 1024,
1017 max_body: 1024 * 1024 * 1024,
1018 buffer_size_ram: 8 * 1024,
1019 buffer_size_fs: 64 * 1024,
1020 size_estimate_deflate: 4,
1021 size_estimate_gzip: 5,
1022 size_estimate_brotli: 6,
1023 temp_dir: env::temp_dir().into(),
1024 }
1025 }
1026
1027 pub fn max_body_ram(&self) -> u64 {
1031 self.max_body_ram
1032 }
1033
1034 pub fn max_body(&self) -> u64 {
1037 self.max_body
1038 }
1039
1040 pub fn buffer_size_ram(&self) -> usize {
1043 self.buffer_size_ram
1044 }
1045
1046 pub fn buffer_size_fs(&self) -> usize {
1049 self.buffer_size_fs
1050 }
1051
1052 pub fn size_estimate_deflate(&self) -> u16 {
1055 self.size_estimate_deflate
1056 }
1057
1058 pub fn size_estimate_gzip(&self) -> u16 {
1061 self.size_estimate_gzip
1062 }
1063
1064 pub fn size_estimate_brotli(&self) -> u16 {
1067 self.size_estimate_brotli
1068 }
1069
1070 pub fn temp_dir(&self) -> &Path {
1073 &self.temp_dir
1074 }
1075
1076 pub fn temp_dir_rc(&self) -> Arc<Path> {
1079 self.temp_dir.clone()
1080 }
1081
1082}
1083
1084impl Default for Tunables {
1085 fn default() -> Self { Tunables::new() }
1086}
1087
1088#[derive(Clone)]
1091pub struct Tuner {
1092 template: Tunables
1093}
1094
1095impl Tuner {
1096 pub fn new() -> Tuner {
1098 Tuner { template: Tunables::new() }
1099 }
1100
1101 pub fn set_max_body_ram(&mut self, size: u64) -> &mut Tuner {
1103 self.template.max_body_ram = size;
1104 self
1105 }
1106
1107 pub fn set_max_body(&mut self, size: u64) -> &mut Tuner {
1111 self.template.max_body = size;
1112 self
1113 }
1114
1115 pub fn set_buffer_size_ram(&mut self, size: usize) -> &mut Tuner {
1117 assert!(size > 0, "buffer_size_ram must be greater than zero");
1118 self.template.buffer_size_ram = size;
1119 self
1120 }
1121
1122 pub fn set_buffer_size_fs(&mut self, size: usize) -> &mut Tuner {
1125 assert!(size > 0, "buffer_size_fs must be greater than zero");
1126 self.template.buffer_size_fs = size;
1127 self
1128 }
1129
1130 pub fn set_size_estimate_deflate(&mut self, multiple: u16) -> &mut Tuner {
1133 assert!(multiple > 0, "size_estimate_deflate must be >= 1");
1134 self.template.size_estimate_deflate = multiple;
1135 self
1136 }
1137
1138 pub fn set_size_estimate_gzip(&mut self, multiple: u16) -> &mut Tuner {
1141 assert!(multiple > 0, "size_estimate_gzip must be >= 1");
1142 self.template.size_estimate_gzip = multiple;
1143 self
1144 }
1145
1146 pub fn set_size_estimate_brotli(&mut self, multiple: u16) -> &mut Tuner {
1149 assert!(multiple > 0, "size_estimate_brotli must be >= 1");
1150 self.template.size_estimate_brotli = multiple;
1151 self
1152 }
1153
1154 pub fn set_temp_dir<P>(&mut self, path: P) -> &mut Tuner
1156 where P: AsRef<Path>
1157 {
1158 self.template.temp_dir = path.as_ref().into();
1159 self
1160 }
1161
1162 pub fn finish(&self) -> Tunables {
1165 let t = self.template.clone();
1166 assert!(t.max_body_ram <= t.max_body,
1167 "max_body_ram can't be greater than max_body");
1168 t
1169 }
1170}
1171
1172impl Default for Tuner {
1173 fn default() -> Self { Tuner::new() }
1174}
1175
1176#[cfg(test)]
1177mod body_tests {
1178 use std::mem::size_of;
1179 use super::*;
1180
1181 fn is_send<T: Send>() -> bool { true }
1182 fn is_sync<T: Sync>() -> bool { true }
1183
1184 type Flaw = Box<dyn StdError + Send + Sync + 'static>;
1185 fn is_flaw(_f: Flaw) -> bool { true }
1186
1187 #[test]
1188 fn test_send_sync() {
1189 assert!(is_send::<BodyError>());
1190 assert!(is_sync::<BodyError>());
1191
1192 assert!(is_send::<BodyImage>());
1193 assert!(is_sync::<BodyImage>());
1194
1195 assert!(is_send::<Dialog>());
1196 assert!(is_sync::<Dialog>());
1197
1198 assert!(is_send::<Tunables>());
1199 assert!(is_sync::<Tunables>());
1200
1201 assert!(is_send::<BodyReader<'_>>());
1202 assert!(is_sync::<BodyReader<'_>>());
1203 }
1204
1205 #[test]
1206 fn test_body_error_size() {
1207 assert!(size_of::<BodyError>() <= 24);
1208 }
1209
1210 #[test]
1211 fn test_body_error_as_flaw() {
1212 assert!(is_flaw(BodyError::BodyTooLong(0).into()));
1213 }
1214
1215 #[test]
1216 fn test_empty_read() {
1217 let body = BodyImage::empty();
1218 let mut br = body.reader();
1219 let mut obuf = Vec::new();
1220 br.read_to_end(&mut obuf).unwrap();
1221 assert!(obuf.is_empty());
1222 }
1223
1224 #[test]
1225 fn test_contiguous_read() {
1226 let mut body = BodySink::with_ram_buffers(2);
1227 body.write_all("hello world").unwrap();
1228 let body = body.prepare().unwrap();
1229 let mut br = body.reader();
1230 let mut obuf = String::new();
1231 br.read_to_string(&mut obuf).unwrap();
1232 assert_eq!("hello world", &obuf[..]);
1233 }
1234
1235 #[test]
1236 fn test_scattered_read() {
1237 let mut body = BodySink::with_ram_buffers(2);
1238 body.write_all("hello").unwrap();
1239 body.write_all(" ").unwrap();
1240 body.write_all("world").unwrap();
1241 let body = body.prepare().unwrap();
1242 let mut br = body.reader();
1243 let mut obuf = String::new();
1244 br.read_to_string(&mut obuf).unwrap();
1245 assert_eq!("hello world", &obuf[..]);
1246 }
1247
1248 #[test]
1249 fn test_scattered_read_clone() {
1250 let mut body = BodySink::with_ram_buffers(2);
1251 body.write_all("hello").unwrap();
1252 body.write_all(" ").unwrap();
1253 body.write_all("world").unwrap();
1254 let mut body = body.prepare().unwrap();
1255 let body_clone = body.clone();
1256 body.gather();
1257
1258 let mut br = body.reader();
1259 let mut obuf = String::new();
1260 br.read_to_string(&mut obuf).unwrap();
1261 assert_eq!("hello world", &obuf[..]);
1262
1263 let mut br = body_clone.reader();
1264 let mut obuf = String::new();
1265 br.read_to_string(&mut obuf).unwrap();
1266 assert_eq!("hello world", &obuf[..]);
1267 }
1268
1269 #[test]
1270 fn test_scattered_gather() {
1271 let mut body = BodySink::with_ram_buffers(2);
1272 body.push(&b"hello"[..]).unwrap();
1273 body.push(&b" "[..]).unwrap();
1274 body.push(&b"world"[..]).unwrap();
1275 let mut body = body.prepare().unwrap();
1276 body.gather();
1277 if let BodyReader::Contiguous(cursor) = body.reader() {
1278 let bslice = cursor.into_inner();
1279 assert_eq!(b"hello world", bslice);
1280 } else {
1281 panic!("not contiguous?!");
1282 }
1283 }
1284
1285 #[test]
1286 fn test_read_from() {
1287 let tune = Tunables::new();
1288 let salutation = b"hello world";
1289 let mut src = Cursor::new(salutation);
1290 let body = BodyImage::read_from(&mut src, 0, &tune).unwrap();
1291 let mut br = body.reader();
1292 let mut obuf = Vec::new();
1293 br.read_to_end(&mut obuf).unwrap();
1294 assert_eq!(salutation, &obuf[..]);
1295 }
1296
1297 #[test]
1298 fn test_read_from_too_long() {
1299 let tune = Tuner::new()
1300 .set_max_body_ram(6)
1301 .set_max_body(6)
1302 .finish();
1303 let salutation = b"hello world";
1304 let mut src = Cursor::new(salutation);
1305 if let Err(e) = BodyImage::read_from(&mut src, 0, &tune) {
1306 if let BodyError::BodyTooLong(l) = e {
1307 assert_eq!(l, salutation.len() as u64)
1308 } else {
1309 panic!("Other error: {}", e);
1310 }
1311 } else {
1312 panic!("Read from, too long, success!?");
1313 }
1314 }
1315
1316 #[test]
1317 fn test_fs_read() {
1318 let tune = Tunables::new();
1319 let mut body = BodySink::with_fs(tune.temp_dir()).unwrap();
1320 body.write_all("hello").unwrap();
1321 body.write_all(" ").unwrap();
1322 body.write_all("world").unwrap();
1323 let body = body.prepare().unwrap();
1324 let mut br = body.reader();
1325 let mut obuf = String::new();
1326 br.read_to_string(&mut obuf).unwrap();
1327 assert_eq!("hello world", &obuf[..]);
1328 }
1329
1330 #[test]
1331 fn test_fs_back_read() {
1332 let tune = Tunables::new();
1333 let mut body = BodySink::with_ram_buffers(2);
1334 body.write_all("hello").unwrap();
1335 body.write_all(" ").unwrap();
1336 body.write_all("world").unwrap();
1337 body.write_back(tune.temp_dir()).unwrap();
1338 let body = body.prepare().unwrap();
1339 let mut br = body.reader();
1340 let mut obuf = String::new();
1341 br.read_to_string(&mut obuf).unwrap();
1342 assert_eq!("hello world", &obuf[..]);
1343 }
1344
1345 #[test]
1346 fn test_w_back_w_read() {
1347 let tune = Tunables::new();
1348 let mut body = BodySink::with_ram_buffers(2);
1349 body.write_all("hello").unwrap();
1350 body.write_back(tune.temp_dir()).unwrap();
1351 body.write_all(" ").unwrap();
1352 body.write_all("world").unwrap();
1353 let body = body.prepare().unwrap();
1354 let mut br = body.reader();
1355 let mut obuf = String::new();
1356 br.read_to_string(&mut obuf).unwrap();
1357 assert_eq!("hello world", &obuf[..]);
1358 }
1359
1360 #[test]
1361 fn test_fs_back_fail() {
1362 let tune = Tuner::new().set_temp_dir("./no-existe/").finish();
1363 let mut body = BodySink::with_ram_buffers(2);
1364 body.write_all("hello").unwrap();
1365 body.write_all(" ").unwrap();
1366 body.write_all("world").unwrap();
1367 if body.write_back(tune.temp_dir()).is_err() {
1368 assert!(body.is_ram());
1369 assert_eq!(body.len(), 0);
1370 } else {
1371 panic!("write_back with bogus dir success?!");
1372 }
1373 }
1374
1375 #[cfg(feature = "mmap")]
1376 #[test]
1377 fn test_fs_map_read() {
1378 let tune = Tunables::new();
1379 let mut body = BodySink::with_fs(tune.temp_dir()).unwrap();
1380 body.write_all("hello").unwrap();
1381 body.write_all(" ").unwrap();
1382 body.write_all("world").unwrap();
1383 let mut body = body.prepare().unwrap();
1384 body.mem_map().unwrap();
1385 let mut br = body.reader();
1386 let mut obuf = String::new();
1387 br.read_to_string(&mut obuf).unwrap();
1388 assert_eq!("hello world", &obuf[..]);
1389 }
1390
1391 #[test]
1392 fn test_fs_back_read_clone() {
1393 let tune = Tunables::new();
1394 let mut body = BodySink::with_ram_buffers(2);
1395 body.write_all("hello").unwrap();
1396 body.write_all(" ").unwrap();
1397 body.write_all("world").unwrap();
1398 body.write_back(tune.temp_dir()).unwrap();
1399 let body = body.prepare().unwrap();
1400
1401 {
1402 let mut br = body.reader();
1403 let mut obuf = String::new();
1404 br.read_to_string(&mut obuf).unwrap();
1405 assert_eq!("hello world", &obuf[..]);
1406 }
1407
1408 let body_clone_1 = body.clone();
1409 let body_clone_2 = body_clone_1.clone();
1410
1411 let mut br = body_clone_1.reader();
1412 let mut obuf = String::new();
1413 br.read_to_string(&mut obuf).unwrap();
1414 assert_eq!("hello world", &obuf[..]);
1415
1416 let mut br = body.reader(); let mut obuf = String::new();
1418 br.read_to_string(&mut obuf).unwrap();
1419 assert_eq!("hello world", &obuf[..]);
1420
1421 let mut br = body_clone_2.reader();
1422 let mut obuf = String::new();
1423 br.read_to_string(&mut obuf).unwrap();
1424 assert_eq!("hello world", &obuf[..]);
1425 }
1426
1427 #[cfg(feature = "mmap")]
1428 #[test]
1429 fn test_fs_map_clone_shared() {
1430 let tune = Tunables::new();
1431 let mut body = BodySink::with_ram_buffers(2);
1432 body.write_all("hello").unwrap();
1433 body.write_all(" ").unwrap();
1434 body.write_all("world").unwrap();
1435 body.write_back(tune.temp_dir()).unwrap();
1436 let mut body = body.prepare().unwrap();
1437 body.mem_map().unwrap();
1438 println!("{:?}", body);
1439
1440 let ptr1 = if let BodyReader::Contiguous(cursor) = body.reader() {
1441 let bslice = cursor.into_inner();
1442 assert_eq!(b"hello world", bslice);
1443 format!("{:p}", bslice)
1444 } else {
1445 panic!("not contiguous?!");
1446 };
1447
1448 let body_clone = body.clone();
1449 println!("{:?}", body_clone);
1450
1451 let ptr2 = if let BodyReader::Contiguous(cursor) = body_clone.reader() {
1452 let bslice = cursor.into_inner();
1453 assert_eq!(b"hello world", bslice);
1454 format!("{:p}", bslice)
1455 } else {
1456 panic!("not contiguous?!");
1457 };
1458
1459 assert_eq!(ptr1, ptr2);
1460 }
1461
1462 #[test]
1463 fn test_fs_empty() {
1464 let tune = Tunables::new();
1465 let body = BodySink::with_fs(tune.temp_dir()).unwrap();
1466 let body = body.prepare().unwrap();
1467 assert!(body.is_empty());
1468 }
1469
1470 #[cfg(feature = "mmap")]
1471 #[test]
1472 fn test_fs_map_empty() {
1473 let tune = Tunables::new();
1474 let body = BodySink::with_fs(tune.temp_dir()).unwrap();
1475 let mut body = body.prepare().unwrap();
1476 body.mem_map().unwrap();
1477 assert!(body.is_empty());
1478 }
1479}