1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//! Describes the generic DataFrame, defining a trait
//! that all dataframes should share. This is so one can
//! optomize the memory footprint of a dataframe for their
//! own needs, and be able to use custom dataframes quickly
use std::io::Write;
use std::borrow::Cow;
use result::WebSocketResult;
use ws::util::header as dfh;
use ws::util::mask::Masker;
use ws::util::mask;

/// A generic DataFrame. Every dataframe should be able to
/// provide these methods. (If the payload is not known in advance then
/// rewrite the write_payload method)
pub trait DataFrame {
    /// Is this dataframe the final dataframe of the message?
    fn is_last(&self) -> bool;
    /// What type of data does this dataframe contain?
    fn opcode(&self) -> u8;
    /// Reserved bits of this dataframe
    fn reserved<'a>(&'a self) -> &'a [bool; 3];
    /// Entire payload of the dataframe. If not known then implement
    /// write_payload as that is the actual method used when sending the
    /// dataframe over the wire.
    fn payload<'a>(&'a self) -> Cow<'a, [u8]>;

    /// How long (in bytes) is this dataframe's payload
    fn size(&self) -> usize {
        self.payload().len()
    }

    /// Write the payload to a writer
    fn write_payload<W>(&self, socket: &mut W) -> WebSocketResult<()>
    where W: Write {
        try!(socket.write_all(&*self.payload()));
        Ok(())
    }

    /// Writes a DataFrame to a Writer.
    fn write_to<W>(&self, writer: &mut W, mask: bool) -> WebSocketResult<()>
	where W: Write {
    	let mut flags = dfh::DataFrameFlags::empty();
    	if self.is_last() {
            flags.insert(dfh::FIN);
        }
        {
            let reserved = self.reserved();
        	if reserved[0] {
                flags.insert(dfh::RSV1);
            }
        	if reserved[1] {
                flags.insert(dfh::RSV2);
            }
        	if reserved[2] {
                flags.insert(dfh::RSV3);
            }
        }

    	let masking_key = if mask {
            Some(mask::gen_mask())
        } else {
            None
        };

    	let header = dfh::DataFrameHeader {
    		flags: flags,
    		opcode: self.opcode() as u8,
    		mask: masking_key,
    		len: self.size() as u64,
    	};

    	try!(dfh::write_header(writer, header));

    	match masking_key {
    		Some(mask) => {
                let mut masker = Masker::new(mask, writer);
                try!(self.write_payload(&mut masker))
            },
    		None => try!(self.write_payload(writer)),
    	};
    	try!(writer.flush());
        Ok(())
    }
}

impl<'a, D> DataFrame for &'a D
where D: DataFrame {
    #[inline(always)]
    fn is_last(&self) -> bool {
        D::is_last(self)
    }

    #[inline(always)]
    fn opcode(&self) -> u8 {
        D::opcode(self)
    }

    #[inline(always)]
    fn reserved<'b>(&'b self) -> &'b [bool; 3] {
        D::reserved(self)
    }

    #[inline(always)]
    fn payload<'b>(&'b self) -> Cow<'b, [u8]> {
        D::payload(self)
    }

    #[inline(always)]
    fn size(&self) -> usize {
        D::size(self)
    }

    #[inline(always)]
    fn write_payload<W>(&self, socket: &mut W) -> WebSocketResult<()>
    where W: Write {
        D::write_payload(self, socket)
    }

    #[inline(always)]
    fn write_to<W>(&self, writer: &mut W, mask: bool) -> WebSocketResult<()>
	where W: Write {
        D::write_to(self, writer, mask)
    }
}