<commit_before>use std::cmp;
use std::fmt;
use std::io::{self, Write};
use std::ptr;

use tokio_io::{AsyncRead, AsyncWrite};

use http::{Http1Transaction, h1, MessageHead, ParseResult, DebugTruncate};
use bytes::{BytesMut, Bytes};

const INIT_BUFFER_SIZE: usize = 8192;
pub const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;

pub struct Buffered<T> {
    io: T,
    read_blocked: bool,
    read_buf: BytesMut,
    write_buf: WriteBuf,
}

impl<T> fmt::Debug for Buffered<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Buffered")
            .field("read_buf", &self.read_buf)
            .field("write_buf", &self.write_buf)
            .finish()
    }
}

impl<T: AsyncRead + AsyncWrite> Buffered<T> {
    pub fn new(io: T) -> Buffered<T> {
        Buffered {
            io: io,
            read_buf: BytesMut::with_capacity(0),
            write_buf: WriteBuf::new(),
            read_blocked: false,
        }
    }

    pub fn read_buf(&self) -> &[u8] {
        self.read_buf.as_ref()
    }

    pub fn consume_leading_lines(&mut self) {
        if !self.read_buf.is_empty() {
            let mut i = 0;
            while i < self.read_buf.len() {
                match self.read_buf[i] {
                    b'\r' | b'\n' => i += 1,
                    _ => break,
                }
            }
            self.read_buf.split_to(i);
        }
    }

    pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> {
        loop {
            match try!(parse::<S, _>(&mut self.read_buf)) {
                Some(head) => {
                    //trace!("parsed {} bytes out of {}", len, self.read_buf.len());
                    return Ok(Some(head.0))
                },
                None => {
                    if self.read_buf.capacity() >= MAX_BUFFER_SIZE {
                        debug!("MAX_BUFFER_SIZE reached, closing");
                        return Err(::Error::TooLarge);
                    }
                },
            }
            self.reserve_read_buf();
            match self.read_from_io() {
                Ok(0) => {
                    trace!("parse eof");
                    return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "parse eof").into());
                }
                Ok(_) => {},
                Err(e) => match e.kind() {
                    io::ErrorKind::WouldBlock => {
                        return Ok(None);
                    },
                    _ => return Err(e.into())
                }
            }
        }
    }

    fn read_from_io(&mut self) -> io::Result<usize> {
        use bytes::BufMut;
        self.read_blocked = false;
        unsafe {
            let n = match self.io.read(self.read_buf.bytes_mut()) {
                Ok(n) => n,
                Err(e) => {
                    if e.kind() == io::ErrorKind::WouldBlock {
                        self.read_blocked = true;
                    }
                    return Err(e)
                }
            };
            self.read_buf.advance_mut(n);
            Ok(n)
        }
    }

    fn reserve_read_buf(&mut self) {
        use bytes::BufMut;
        if self.read_buf.remaining_mut() >= INIT_BUFFER_SIZE {
            return
        }
        self.read_buf.reserve(INIT_BUFFER_SIZE);
        unsafe {
            let buf = self.read_buf.bytes_mut();
            let len = buf.len();
            ptr::write_bytes(buf.as_mut_ptr(), 0, len);
        }
    }

    pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) -> usize {
        self.write_buf.buffer(buf.as_ref())
    }

    pub fn io_mut(&mut self) -> &mut T {
        &mut self.io
    }

    pub fn is_read_blocked(&self) -> bool {
        self.read_blocked
    }
}

impl<T: Write> Write for Buffered<T> {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Ok(self.write_buf.buffer(data))
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.write_buf.remaining() == 0 {
            self.io.flush()
        } else {
            loop {
                let n = try!(self.write_buf.write_into(&mut self.io));
                debug!("flushed {} bytes", n);
                if self.write_buf.remaining() == 0 {
                    break;
                }
            }
            self.io.flush()
        }
    }
}

fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &mut BytesMut) -> ParseResult<I> {
    h1::parse::<T, I>(rdr)
}

pub trait MemRead {
    fn read_mem(&mut self, len: usize) -> io::Result<Bytes>;
}

impl<T: AsyncRead + AsyncWrite> MemRead for Buffered<T> {
    fn read_mem(&mut self, len: usize) -> io::Result<Bytes> {
        trace!("Buffered.read_mem read_buf={}, wanted={}", self.read_buf.len(), len);
        if !self.read_buf.is_empty() {
            let n = ::std::cmp::min(len, self.read_buf.len());
            trace!("Buffered.read_mem read_buf is not empty, slicing {}", n);
            Ok(self.read_buf.split_to(n).freeze())
        } else {
            self.reserve_read_buf();
            let n = try!(self.read_from_io());
            Ok(self.read_buf.split_to(::std::cmp::min(len, n)).freeze())
        }
    }
}

#[derive(Clone)]
pub struct Cursor<T> {
    bytes: T,
    pos: usize,
}

impl<T: AsRef<[u8]>> Cursor<T> {
    pub fn new(bytes: T) -> Cursor<T> {
        Cursor {
            bytes: bytes,
            pos: 0,
        }
    }

    pub fn is_written(&self) -> bool {
        trace!("Cursor::is_written pos = {}, len = {}", self.pos, self.bytes.as_ref().len());
        self.pos >= self.bytes.as_ref().len()
    }

    pub fn write_to<W: Write>(&mut self, dst: &mut W) -> io::Result<usize> {
        if self.remaining() == 0 {
            Ok(0)
        } else {
            dst.write(&self.bytes.as_ref()[self.pos..]).map(|n| {
                self.pos += n;
                n
            })
        }
    }

    fn remaining(&self) -> usize {
        self.bytes.as_ref().len() - self.pos
    }

    #[inline]
    pub fn buf(&self) -> &[u8] {
        &self.bytes.as_ref()[self.pos..]
    }

    #[inline]
    pub fn consume(&mut self, num: usize) {
        trace!("Cursor::consume({})", num);
        self.pos = ::std::cmp::min(self.bytes.as_ref().len(), self.pos + num);
    }
}

impl<T: AsRef<[u8]>> fmt::Debug for Cursor<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("Cursor")
            .field(&DebugTruncate(self.buf()))
            .finish()
    }
}

pub trait AtomicWrite {
    fn write_atomic(&mut self, data: &[&[u8]]) -> io::Result<usize>;
}

/*
#[cfg(not(windows))]
impl<T: Write + ::vecio::Writev> AtomicWrite for T {

    fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
        self.writev(bufs)
    }

}

#[cfg(windows)]
*/
impl<T: Write> AtomicWrite for T {
    fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
        if bufs.len() == 1 {
            self.write(bufs[0])
        } else {
            let vec = bufs.concat();
            self.write(&vec)
        }
    }
}
//}

// an internal buffer to collect writes before flushes
#[derive(Debug)]
struct WriteBuf(Cursor<Vec<u8>>);

impl WriteBuf {
    fn new() -> WriteBuf {
        WriteBuf(Cursor::new(Vec::new()))
    }

    fn write_into<W: Write>(&mut self, w: &mut W) -> io::Result<usize> {
        self.0.write_to(w)
    }

    fn buffer(&mut self, data: &[u8]) -> usize {
        trace!("WriteBuf::buffer() len = {:?}", data.len());
        self.maybe_reset();
        self.maybe_reserve(data.len());
        let mut vec = &mut self.0.bytes;
        let len = cmp::min(vec.capacity() - vec.len(), data.len());
        assert!(vec.capacity() - vec.len() >= len);
        unsafe {
            // in rust 1.9, we could use slice::copy_from_slice
            ptr::copy(
                data.as_ptr(),
                vec.as_mut_ptr().offset(vec.len() as isize),
                len
            );
            let new_len = vec.len() + len;
            vec.set_len(new_len);
        }
        len
    }

    fn remaining(&self) -> usize {
        self.0.remaining()
    }

    #[inline]
    fn maybe_reserve(&mut self, needed: usize) {
        let mut vec = &mut self.0.bytes;
        let cap = vec.capacity();
        if cap == 0 {
            let init = cmp::min(MAX_BUFFER_SIZE, cmp::max(INIT_BUFFER_SIZE, needed));
            trace!("WriteBuf reserving initial {}", init);
            vec.reserve(init);
        } else if cap < MAX_BUFFER_SIZE {
            vec.reserve(cmp::min(needed, MAX_BUFFER_SIZE - cap));
            trace!("WriteBuf reserved {}", vec.capacity() - cap);
        }
    }

    fn maybe_reset(&mut self) {
        if self.0.pos != 0 && self.0.remaining() == 0 {
            self.0.pos = 0;
            unsafe {
                self.0.bytes.set_len(0);
            }
        }
    }
}

#[cfg(test)]
use std::io::Read;

#[cfg(test)]
impl<T: Read> MemRead for ::mock::AsyncIo<T> {
    fn read_mem(&mut self, len: usize) -> io::Result<Bytes> {
        let mut v = vec![0; len];
        let n = try!(self.read(v.as_mut_slice()));
        Ok(BytesMut::from(&v[..n]).freeze())
    }
}

#[test]
fn test_iobuf_write_empty_slice() {
    use mock::{AsyncIo, Buf as MockBuf};

    let mut mock = AsyncIo::new(MockBuf::new(), 256);
    mock.error(io::Error::new(io::ErrorKind::Other, "logic error"));

    let mut io_buf = Buffered::new(mock);

    // underlying io will return the logic error upon write,
    // so we are testing that the io_buf does not trigger a write
    // when there is nothing to flush
    io_buf.flush().expect("should short-circuit flush");
}

#[test]
fn test_parse_reads_until_blocked() {
    use mock::{AsyncIo, Buf as MockBuf};
    // missing last line ending
    let raw = "HTTP/1.1 200 OK\r\n";

    let mock = AsyncIo::new(MockBuf::wrap(raw.into()), raw.len());
    let mut buffered = Buffered::new(mock);
    assert_eq!(buffered.parse::<super::ClientTransaction>().unwrap(), None);
    assert!(buffered.io.blocked());
}
<commit_msg>perf(http): use custom type for ParseEof error instead of string error<commit_after>use std::cmp;
use std::fmt;
use std::io::{self, Write};
use std::ptr;

use tokio_io::{AsyncRead, AsyncWrite};

use http::{Http1Transaction, h1, MessageHead, ParseResult, DebugTruncate};
use bytes::{BytesMut, Bytes};

const INIT_BUFFER_SIZE: usize = 8192;
pub const MAX_BUFFER_SIZE: usize = 8192 + 4096 * 100;

pub struct Buffered<T> {
    io: T,
    read_blocked: bool,
    read_buf: BytesMut,
    write_buf: WriteBuf,
}

impl<T> fmt::Debug for Buffered<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Buffered")
            .field("read_buf", &self.read_buf)
            .field("write_buf", &self.write_buf)
            .finish()
    }
}

impl<T: AsyncRead + AsyncWrite> Buffered<T> {
    pub fn new(io: T) -> Buffered<T> {
        Buffered {
            io: io,
            read_buf: BytesMut::with_capacity(0),
            write_buf: WriteBuf::new(),
            read_blocked: false,
        }
    }

    pub fn read_buf(&self) -> &[u8] {
        self.read_buf.as_ref()
    }

    pub fn consume_leading_lines(&mut self) {
        if !self.read_buf.is_empty() {
            let mut i = 0;
            while i < self.read_buf.len() {
                match self.read_buf[i] {
                    b'\r' | b'\n' => i += 1,
                    _ => break,
                }
            }
            self.read_buf.split_to(i);
        }
    }

    pub fn parse<S: Http1Transaction>(&mut self) -> ::Result<Option<MessageHead<S::Incoming>>> {
        loop {
            match try!(parse::<S, _>(&mut self.read_buf)) {
                Some(head) => {
                    //trace!("parsed {} bytes out of {}", len, self.read_buf.len());
                    return Ok(Some(head.0))
                },
                None => {
                    if self.read_buf.capacity() >= MAX_BUFFER_SIZE {
                        debug!("MAX_BUFFER_SIZE reached, closing");
                        return Err(::Error::TooLarge);
                    }
                },
            }
            self.reserve_read_buf();
            match self.read_from_io() {
                Ok(0) => {
                    trace!("parse eof");
                    //TODO: With Rust 1.14, this can be Error::from(ErrorKind)
                    return Err(io::Error::new(io::ErrorKind::UnexpectedEof, ParseEof).into());
                }
                Ok(_) => {},
                Err(e) => match e.kind() {
                    io::ErrorKind::WouldBlock => {
                        return Ok(None);
                    },
                    _ => return Err(e.into())
                }
            }
        }
    }

    fn read_from_io(&mut self) -> io::Result<usize> {
        use bytes::BufMut;
        self.read_blocked = false;
        unsafe {
            let n = match self.io.read(self.read_buf.bytes_mut()) {
                Ok(n) => n,
                Err(e) => {
                    if e.kind() == io::ErrorKind::WouldBlock {
                        self.read_blocked = true;
                    }
                    return Err(e)
                }
            };
            self.read_buf.advance_mut(n);
            Ok(n)
        }
    }

    fn reserve_read_buf(&mut self) {
        use bytes::BufMut;
        if self.read_buf.remaining_mut() >= INIT_BUFFER_SIZE {
            return
        }
        self.read_buf.reserve(INIT_BUFFER_SIZE);
        unsafe {
            let buf = self.read_buf.bytes_mut();
            let len = buf.len();
            ptr::write_bytes(buf.as_mut_ptr(), 0, len);
        }
    }

    pub fn buffer<B: AsRef<[u8]>>(&mut self, buf: B) -> usize {
        self.write_buf.buffer(buf.as_ref())
    }

    pub fn io_mut(&mut self) -> &mut T {
        &mut self.io
    }

    pub fn is_read_blocked(&self) -> bool {
        self.read_blocked
    }
}

impl<T: Write> Write for Buffered<T> {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Ok(self.write_buf.buffer(data))
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.write_buf.remaining() == 0 {
            self.io.flush()
        } else {
            loop {
                let n = try!(self.write_buf.write_into(&mut self.io));
                debug!("flushed {} bytes", n);
                if self.write_buf.remaining() == 0 {
                    break;
                }
            }
            self.io.flush()
        }
    }
}

fn parse<T: Http1Transaction<Incoming=I>, I>(rdr: &mut BytesMut) -> ParseResult<I> {
    h1::parse::<T, I>(rdr)
}

pub trait MemRead {
    fn read_mem(&mut self, len: usize) -> io::Result<Bytes>;
}

impl<T: AsyncRead + AsyncWrite> MemRead for Buffered<T> {
    fn read_mem(&mut self, len: usize) -> io::Result<Bytes> {
        trace!("Buffered.read_mem read_buf={}, wanted={}", self.read_buf.len(), len);
        if !self.read_buf.is_empty() {
            let n = ::std::cmp::min(len, self.read_buf.len());
            trace!("Buffered.read_mem read_buf is not empty, slicing {}", n);
            Ok(self.read_buf.split_to(n).freeze())
        } else {
            self.reserve_read_buf();
            let n = try!(self.read_from_io());
            Ok(self.read_buf.split_to(::std::cmp::min(len, n)).freeze())
        }
    }
}

#[derive(Clone)]
pub struct Cursor<T> {
    bytes: T,
    pos: usize,
}

impl<T: AsRef<[u8]>> Cursor<T> {
    pub fn new(bytes: T) -> Cursor<T> {
        Cursor {
            bytes: bytes,
            pos: 0,
        }
    }

    pub fn is_written(&self) -> bool {
        trace!("Cursor::is_written pos = {}, len = {}", self.pos, self.bytes.as_ref().len());
        self.pos >= self.bytes.as_ref().len()
    }

    pub fn write_to<W: Write>(&mut self, dst: &mut W) -> io::Result<usize> {
        if self.remaining() == 0 {
            Ok(0)
        } else {
            dst.write(&self.bytes.as_ref()[self.pos..]).map(|n| {
                self.pos += n;
                n
            })
        }
    }

    fn remaining(&self) -> usize {
        self.bytes.as_ref().len() - self.pos
    }

    #[inline]
    pub fn buf(&self) -> &[u8] {
        &self.bytes.as_ref()[self.pos..]
    }

    #[inline]
    pub fn consume(&mut self, num: usize) {
        trace!("Cursor::consume({})", num);
        self.pos = ::std::cmp::min(self.bytes.as_ref().len(), self.pos + num);
    }
}

impl<T: AsRef<[u8]>> fmt::Debug for Cursor<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("Cursor")
            .field(&DebugTruncate(self.buf()))
            .finish()
    }
}

pub trait AtomicWrite {
    fn write_atomic(&mut self, data: &[&[u8]]) -> io::Result<usize>;
}

/*
#[cfg(not(windows))]
impl<T: Write + ::vecio::Writev> AtomicWrite for T {

    fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
        self.writev(bufs)
    }

}

#[cfg(windows)]
*/
impl<T: Write> AtomicWrite for T {
    fn write_atomic(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
        if bufs.len() == 1 {
            self.write(bufs[0])
        } else {
            let vec = bufs.concat();
            self.write(&vec)
        }
    }
}
//}

// an internal buffer to collect writes before flushes
#[derive(Debug)]
struct WriteBuf(Cursor<Vec<u8>>);

impl WriteBuf {
    fn new() -> WriteBuf {
        WriteBuf(Cursor::new(Vec::new()))
    }

    fn write_into<W: Write>(&mut self, w: &mut W) -> io::Result<usize> {
        self.0.write_to(w)
    }

    fn buffer(&mut self, data: &[u8]) -> usize {
        trace!("WriteBuf::buffer() len = {:?}", data.len());
        self.maybe_reset();
        self.maybe_reserve(data.len());
        let mut vec = &mut self.0.bytes;
        let len = cmp::min(vec.capacity() - vec.len(), data.len());
        assert!(vec.capacity() - vec.len() >= len);
        unsafe {
            // in rust 1.9, we could use slice::copy_from_slice
            ptr::copy(
                data.as_ptr(),
                vec.as_mut_ptr().offset(vec.len() as isize),
                len
            );
            let new_len = vec.len() + len;
            vec.set_len(new_len);
        }
        len
    }

    fn remaining(&self) -> usize {
        self.0.remaining()
    }

    #[inline]
    fn maybe_reserve(&mut self, needed: usize) {
        let mut vec = &mut self.0.bytes;
        let cap = vec.capacity();
        if cap == 0 {
            let init = cmp::min(MAX_BUFFER_SIZE, cmp::max(INIT_BUFFER_SIZE, needed));
            trace!("WriteBuf reserving initial {}", init);
            vec.reserve(init);
        } else if cap < MAX_BUFFER_SIZE {
            vec.reserve(cmp::min(needed, MAX_BUFFER_SIZE - cap));
            trace!("WriteBuf reserved {}", vec.capacity() - cap);
        }
    }

    fn maybe_reset(&mut self) {
        if self.0.pos != 0 && self.0.remaining() == 0 {
            self.0.pos = 0;
            unsafe {
                self.0.bytes.set_len(0);
            }
        }
    }
}

#[derive(Debug)]
struct ParseEof;

impl fmt::Display for ParseEof {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("parse eof")
    }
}

impl ::std::error::Error for ParseEof {
    fn description(&self) -> &str {
        "parse eof"
    }
}

#[cfg(test)]
use std::io::Read;

#[cfg(test)]
impl<T: Read> MemRead for ::mock::AsyncIo<T> {
    fn read_mem(&mut self, len: usize) -> io::Result<Bytes> {
        let mut v = vec![0; len];
        let n = try!(self.read(v.as_mut_slice()));
        Ok(BytesMut::from(&v[..n]).freeze())
    }
}

#[test]
fn test_iobuf_write_empty_slice() {
    use mock::{AsyncIo, Buf as MockBuf};

    let mut mock = AsyncIo::new(MockBuf::new(), 256);
    mock.error(io::Error::new(io::ErrorKind::Other, "logic error"));

    let mut io_buf = Buffered::new(mock);

    // underlying io will return the logic error upon write,
    // so we are testing that the io_buf does not trigger a write
    // when there is nothing to flush
    io_buf.flush().expect("should short-circuit flush");
}

#[test]
fn test_parse_reads_until_blocked() {
    use mock::{AsyncIo, Buf as MockBuf};
    // missing last line ending
    let raw = "HTTP/1.1 200 OK\r\n";

    let mock = AsyncIo::new(MockBuf::wrap(raw.into()), raw.len());
    let mut buffered = Buffered::new(mock);
    assert_eq!(buffered.parse::<super::ClientTransaction>().unwrap(), None);
    assert!(buffered.io.blocked());
}
<|endoftext|>


<commit_before>use regex::{Regex, Captures};
use rustc_serialize::json::Json;

use hyper::method::Method;
use hyper::method::Method::{Get, Post, Delete};

use command::{WebDriverCommand, WebDriverMessage, WebDriverExtensionCommand,
              VoidWebDriverExtensionCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};

fn standard_routes<U:WebDriverExtensionRoute>() -> Vec<(Method, &'static str, Route<U>)> {
    return vec![(Post, "/session", Route::NewSession),
                (Delete, "/session/{sessionId}", Route::DeleteSession),
                (Post, "/session/{sessionId}/url", Route::Get),
                (Get, "/session/{sessionId}/url", Route::GetCurrentUrl),
                (Post, "/session/{sessionId}/back", Route::GoBack),
                (Post, "/session/{sessionId}/forward", Route::GoForward),
                (Post, "/session/{sessionId}/refresh", Route::Refresh),
                (Get, "/session/{sessionId}/title", Route::GetTitle),
                (Get, "/session/{sessionId}/source", Route::GetPageSource),
                (Get, "/session/{sessionId}/window", Route::GetWindowHandle),
                (Get, "/session/{sessionId}/window/handles", Route::GetWindowHandles),
                (Delete, "/session/{sessionId}/window", Route::CloseWindow),
                (Get, "/session/{sessionId}/window/size", Route::GetWindowSize),
                (Post, "/session/{sessionId}/window/size", Route::SetWindowSize),
                (Get, "/session/{sessionId}/window/position", Route::GetWindowPosition),
                (Post, "/session/{sessionId}/window/position", Route::SetWindowPosition),
                (Post, "/session/{sessionId}/window/maximize", Route::MaximizeWindow),
                (Post, "/session/{sessionId}/window", Route::SwitchToWindow),
                (Post, "/session/{sessionId}/frame", Route::SwitchToFrame),
                (Post, "/session/{sessionId}/frame/parent", Route::SwitchToParentFrame),
                (Post, "/session/{sessionId}/element", Route::FindElement),
                (Post, "/session/{sessionId}/elements", Route::FindElements),
                (Post, "/session/{sessionId}/element/{elementId}/element", Route::FindElementElement),
                (Post, "/session/{sessionId}/element/{elementId}/elements", Route::FindElementElements),
                (Get, "/session/{sessionId}/element/active", Route::GetActiveElement),
                (Get, "/session/{sessionId}/element/{elementId}/displayed", Route::IsDisplayed),
                (Get, "/session/{sessionId}/element/{elementId}/selected", Route::IsSelected),
                (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", Route::GetElementAttribute),
                (Get, "/session/{sessionId}/element/{elementId}/property/{name}", Route::GetElementProperty),
                (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", Route::GetCSSValue),
                (Get, "/session/{sessionId}/element/{elementId}/text", Route::GetElementText),
                (Get, "/session/{sessionId}/element/{elementId}/name", Route::GetElementTagName),
                (Get, "/session/{sessionId}/element/{elementId}/rect", Route::GetElementRect),
                (Get, "/session/{sessionId}/element/{elementId}/enabled", Route::IsEnabled),
                (Post, "/session/{sessionId}/execute/sync", Route::ExecuteScript),
                (Post, "/session/{sessionId}/execute/async", Route::ExecuteAsyncScript),
                (Get, "/session/{sessionId}/cookie", Route::GetCookies),
                (Get, "/session/{sessionId}/cookie/{name}", Route::GetNamedCookie),
                (Post, "/session/{sessionId}/cookie", Route::AddCookie),
                (Delete, "/session/{sessionId}/cookie", Route::DeleteCookies),
                (Delete, "/session/{sessionId}/cookie/{name}", Route::DeleteCookie),
                (Get, "/session/{sessionId}/timeouts", Route::GetTimeouts),
                (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts),
                //(Post, "/session/{sessionId}/actions", Route::Actions),
                (Post, "/session/{sessionId}/element/{elementId}/click", Route::ElementClick),
                (Post, "/session/{sessionId}/element/{elementId}/tap", Route::ElementTap),
                (Post, "/session/{sessionId}/element/{elementId}/clear", Route::ElementClear),
                (Post, "/session/{sessionId}/element/{elementId}/value", Route::ElementSendKeys),
                (Post, "/session/{sessionId}/alert/dismiss", Route::DismissAlert),
                (Post, "/session/{sessionId}/alert/accept", Route::AcceptAlert),
                (Get, "/session/{sessionId}/alert/text", Route::GetAlertText),
                (Post, "/session/{sessionId}/alert/text", Route::SendAlertText),
                (Get, "/session/{sessionId}/screenshot", Route::TakeScreenshot),
                (Get, "/session/{sessionId}/element/{elementId}/screenshot", Route::TakeElementScreenshot),
                (Post, "/session/{sessionId}/actions", Route::PerformActions),
                (Delete, "/session/{sessionId}/actions", Route::ReleaseActions),
                // TODO Remove this when > v0.5 is released. There for compatibility reasons with existing
                //      Webdriver implementations.
                (Get, "/session/{sessionId}/alert_text", Route::GetAlertText),
                (Post, "/session/{sessionId}/alert_text", Route::SendAlertText),
                (Post, "/session/{sessionId}/accept_alert", Route::AcceptAlert),
                (Post, "/session/{sessionId}/dismiss_alert", Route::DismissAlert),
                (Get, "/session/{sessionId}/window_handle", Route::GetWindowHandle),
                (Get, "/session/{sessionId}/window_handles", Route::GetWindowHandles),
                (Delete, "/session/{sessionId}/window_handle", Route::CloseWindow),
                (Post, "/session/{sessionId}/execute_async", Route::ExecuteAsyncScript),
                (Post, "/session/{sessionId}/execute", Route::ExecuteScript),
                (Get, "/status", Route::Status),]
}

#[derive(Clone, Copy)]
pub enum Route<U:WebDriverExtensionRoute> {
    NewSession,
    DeleteSession,
    Get,
    GetCurrentUrl,
    GoBack,
    GoForward,
    Refresh,
    GetTitle,
    GetPageSource,
    GetWindowHandle,
    GetWindowHandles,
    CloseWindow,
    GetWindowSize,
    SetWindowSize,
    GetWindowPosition,
    SetWindowPosition,
    MaximizeWindow,
    SwitchToWindow,
    SwitchToFrame,
    SwitchToParentFrame,
    FindElement,
    FindElements,
    FindElementElement,
    FindElementElements,
    GetActiveElement,
    IsDisplayed,
    IsSelected,
    GetElementAttribute,
    GetElementProperty,
    GetCSSValue,
    GetElementText,
    GetElementTagName,
    GetElementRect,
    IsEnabled,
    ExecuteScript,
    ExecuteAsyncScript,
    GetCookies,
    GetNamedCookie,
    AddCookie,
    DeleteCookies,
    DeleteCookie,
    GetTimeouts,
    SetTimeouts,
    ElementClick,
    ElementTap,
    ElementClear,
    ElementSendKeys,
    PerformActions,
    ReleaseActions,
    DismissAlert,
    AcceptAlert,
    GetAlertText,
    SendAlertText,
    TakeScreenshot,
    TakeElementScreenshot,
    Status,
    Extension(U),
}

pub trait WebDriverExtensionRoute : Clone + Send + PartialEq {
    type Command: WebDriverExtensionCommand + 'static;

    fn command(&self, &Captures, &Json) -> WebDriverResult<WebDriverCommand<Self::Command>>;
}

#[derive(Clone, PartialEq)]
pub struct VoidWebDriverExtensionRoute;

impl WebDriverExtensionRoute for VoidWebDriverExtensionRoute {
    type Command = VoidWebDriverExtensionCommand;

    fn command(&self, _:&Captures, _:&Json) -> WebDriverResult<WebDriverCommand<VoidWebDriverExtensionCommand>> {
        panic!("No extensions implemented");
    }
}

#[derive(Clone)]
struct RequestMatcher<U: WebDriverExtensionRoute> {
    method: Method,
    path_regexp: Regex,
    match_type: Route<U>
}

impl <U: WebDriverExtensionRoute> RequestMatcher<U> {
    pub fn new(method: Method, path: &str, match_type: Route<U>) -> RequestMatcher<U> {
        let path_regexp = RequestMatcher::<U>::compile_path(path);
        RequestMatcher {
            method: method,
            path_regexp: path_regexp,
            match_type: match_type
        }
    }

    pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
        let captures = self.path_regexp.captures(path);
        (method == self.method, captures)
    }

    fn compile_path(path: &str) -> Regex {
        let mut rv = String::new();
        rv.push_str("^");
        let components = path.split('/');
        for component in components {
            if component.starts_with("{") {
                if !component.ends_with("}") {
                    panic!("Invalid url pattern")
                }
                rv.push_str(&format!("(?P<{}>[^/]+)/", &component[1..component.len()-1])[..]);
            } else {
                rv.push_str(&format!("{}/", component)[..]);
            }
        }
        //Remove the trailing /
        rv.pop();
        rv.push_str("$");
        //This will fail at runtime if the regexp is invalid
        Regex::new(&rv[..]).unwrap()
    }
}

pub struct WebDriverHttpApi<U: WebDriverExtensionRoute> {
    routes: Vec<(Method, RequestMatcher<U>)>,
}

impl <U: WebDriverExtensionRoute> WebDriverHttpApi<U> {
    pub fn new(extension_routes: &[(Method, &str, U)]) -> WebDriverHttpApi<U> {
        let mut rv = WebDriverHttpApi::<U> {
            routes: vec![],
        };
        debug!("Creating routes");
        for &(ref method, ref url, ref match_type) in standard_routes::<U>().iter() {
            rv.add(method.clone(), *url, (*match_type).clone());
        };
        for &(ref method, ref url, ref extension_route) in extension_routes.iter() {
            rv.add(method.clone(), *url, Route::Extension(extension_route.clone()));
        };
        rv
    }

    fn add(&mut self, method: Method, path: &str, match_type: Route<U>) {
        let http_matcher = RequestMatcher::new(method.clone(), path, match_type);
        self.routes.push((method, http_matcher));
    }

    pub fn decode_request(&self, method: Method, path: &str, body: &str) -> WebDriverResult<WebDriverMessage<U>> {
        let mut error = ErrorStatus::UnknownPath;
        for &(ref match_method, ref matcher) in self.routes.iter() {
            if method == *match_method {
                let (method_match, captures) = matcher.get_match(method.clone(), path);
                if captures.is_some() {
                    if method_match {
                        return WebDriverMessage::from_http(matcher.match_type.clone(),
                                                           &captures.unwrap(),
                                                           body,
                                                           method == Post)
                    } else {
                        error = ErrorStatus::UnknownMethod;
                    }
                }
            }
        }
        Err(WebDriverError::new(error,
                                format!("{} {} did not match a known command", method, path)))
    }
}
<commit_msg>Remove end points no longer supported by Selenium.<commit_after>use regex::{Regex, Captures};
use rustc_serialize::json::Json;

use hyper::method::Method;
use hyper::method::Method::{Get, Post, Delete};

use command::{WebDriverCommand, WebDriverMessage, WebDriverExtensionCommand,
              VoidWebDriverExtensionCommand};
use error::{WebDriverResult, WebDriverError, ErrorStatus};

fn standard_routes<U:WebDriverExtensionRoute>() -> Vec<(Method, &'static str, Route<U>)> {
    return vec![(Post, "/session", Route::NewSession),
                (Delete, "/session/{sessionId}", Route::DeleteSession),
                (Post, "/session/{sessionId}/url", Route::Get),
                (Get, "/session/{sessionId}/url", Route::GetCurrentUrl),
                (Post, "/session/{sessionId}/back", Route::GoBack),
                (Post, "/session/{sessionId}/forward", Route::GoForward),
                (Post, "/session/{sessionId}/refresh", Route::Refresh),
                (Get, "/session/{sessionId}/title", Route::GetTitle),
                (Get, "/session/{sessionId}/source", Route::GetPageSource),
                (Get, "/session/{sessionId}/window", Route::GetWindowHandle),
                (Get, "/session/{sessionId}/window/handles", Route::GetWindowHandles),
                (Delete, "/session/{sessionId}/window", Route::CloseWindow),
                (Get, "/session/{sessionId}/window/size", Route::GetWindowSize),
                (Post, "/session/{sessionId}/window/size", Route::SetWindowSize),
                (Get, "/session/{sessionId}/window/position", Route::GetWindowPosition),
                (Post, "/session/{sessionId}/window/position", Route::SetWindowPosition),
                (Post, "/session/{sessionId}/window/maximize", Route::MaximizeWindow),
                (Post, "/session/{sessionId}/window", Route::SwitchToWindow),
                (Post, "/session/{sessionId}/frame", Route::SwitchToFrame),
                (Post, "/session/{sessionId}/frame/parent", Route::SwitchToParentFrame),
                (Post, "/session/{sessionId}/element", Route::FindElement),
                (Post, "/session/{sessionId}/elements", Route::FindElements),
                (Post, "/session/{sessionId}/element/{elementId}/element", Route::FindElementElement),
                (Post, "/session/{sessionId}/element/{elementId}/elements", Route::FindElementElements),
                (Get, "/session/{sessionId}/element/active", Route::GetActiveElement),
                (Get, "/session/{sessionId}/element/{elementId}/displayed", Route::IsDisplayed),
                (Get, "/session/{sessionId}/element/{elementId}/selected", Route::IsSelected),
                (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", Route::GetElementAttribute),
                (Get, "/session/{sessionId}/element/{elementId}/property/{name}", Route::GetElementProperty),
                (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", Route::GetCSSValue),
                (Get, "/session/{sessionId}/element/{elementId}/text", Route::GetElementText),
                (Get, "/session/{sessionId}/element/{elementId}/name", Route::GetElementTagName),
                (Get, "/session/{sessionId}/element/{elementId}/rect", Route::GetElementRect),
                (Get, "/session/{sessionId}/element/{elementId}/enabled", Route::IsEnabled),
                (Post, "/session/{sessionId}/execute/sync", Route::ExecuteScript),
                (Post, "/session/{sessionId}/execute/async", Route::ExecuteAsyncScript),
                (Get, "/session/{sessionId}/cookie", Route::GetCookies),
                (Get, "/session/{sessionId}/cookie/{name}", Route::GetNamedCookie),
                (Post, "/session/{sessionId}/cookie", Route::AddCookie),
                (Delete, "/session/{sessionId}/cookie", Route::DeleteCookies),
                (Delete, "/session/{sessionId}/cookie/{name}", Route::DeleteCookie),
                (Get, "/session/{sessionId}/timeouts", Route::GetTimeouts),
                (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts),
                (Post, "/session/{sessionId}/element/{elementId}/click", Route::ElementClick),
                (Post, "/session/{sessionId}/element/{elementId}/tap", Route::ElementTap),
                (Post, "/session/{sessionId}/element/{elementId}/clear", Route::ElementClear),
                (Post, "/session/{sessionId}/element/{elementId}/value", Route::ElementSendKeys),
                (Post, "/session/{sessionId}/alert/dismiss", Route::DismissAlert),
                (Post, "/session/{sessionId}/alert/accept", Route::AcceptAlert),
                (Get, "/session/{sessionId}/alert/text", Route::GetAlertText),
                (Post, "/session/{sessionId}/alert/text", Route::SendAlertText),
                (Get, "/session/{sessionId}/screenshot", Route::TakeScreenshot),
                (Get, "/session/{sessionId}/element/{elementId}/screenshot", Route::TakeElementScreenshot),
                (Post, "/session/{sessionId}/actions", Route::PerformActions),
                (Delete, "/session/{sessionId}/actions", Route::ReleaseActions),
                (Get, "/status", Route::Status),]
}

#[derive(Clone, Copy)]
pub enum Route<U:WebDriverExtensionRoute> {
    NewSession,
    DeleteSession,
    Get,
    GetCurrentUrl,
    GoBack,
    GoForward,
    Refresh,
    GetTitle,
    GetPageSource,
    GetWindowHandle,
    GetWindowHandles,
    CloseWindow,
    GetWindowSize,
    SetWindowSize,
    GetWindowPosition,
    SetWindowPosition,
    MaximizeWindow,
    SwitchToWindow,
    SwitchToFrame,
    SwitchToParentFrame,
    FindElement,
    FindElements,
    FindElementElement,
    FindElementElements,
    GetActiveElement,
    IsDisplayed,
    IsSelected,
    GetElementAttribute,
    GetElementProperty,
    GetCSSValue,
    GetElementText,
    GetElementTagName,
    GetElementRect,
    IsEnabled,
    ExecuteScript,
    ExecuteAsyncScript,
    GetCookies,
    GetNamedCookie,
    AddCookie,
    DeleteCookies,
    DeleteCookie,
    GetTimeouts,
    SetTimeouts,
    ElementClick,
    ElementTap,
    ElementClear,
    ElementSendKeys,
    PerformActions,
    ReleaseActions,
    DismissAlert,
    AcceptAlert,
    GetAlertText,
    SendAlertText,
    TakeScreenshot,
    TakeElementScreenshot,
    Status,
    Extension(U),
}

pub trait WebDriverExtensionRoute : Clone + Send + PartialEq {
    type Command: WebDriverExtensionCommand + 'static;

    fn command(&self, &Captures, &Json) -> WebDriverResult<WebDriverCommand<Self::Command>>;
}

#[derive(Clone, PartialEq)]
pub struct VoidWebDriverExtensionRoute;

impl WebDriverExtensionRoute for VoidWebDriverExtensionRoute {
    type Command = VoidWebDriverExtensionCommand;

    fn command(&self, _:&Captures, _:&Json) -> WebDriverResult<WebDriverCommand<VoidWebDriverExtensionCommand>> {
        panic!("No extensions implemented");
    }
}

#[derive(Clone)]
struct RequestMatcher<U: WebDriverExtensionRoute> {
    method: Method,
    path_regexp: Regex,
    match_type: Route<U>
}

impl <U: WebDriverExtensionRoute> RequestMatcher<U> {
    pub fn new(method: Method, path: &str, match_type: Route<U>) -> RequestMatcher<U> {
        let path_regexp = RequestMatcher::<U>::compile_path(path);
        RequestMatcher {
            method: method,
            path_regexp: path_regexp,
            match_type: match_type
        }
    }

    pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
        let captures = self.path_regexp.captures(path);
        (method == self.method, captures)
    }

    fn compile_path(path: &str) -> Regex {
        let mut rv = String::new();
        rv.push_str("^");
        let components = path.split('/');
        for component in components {
            if component.starts_with("{") {
                if !component.ends_with("}") {
                    panic!("Invalid url pattern")
                }
                rv.push_str(&format!("(?P<{}>[^/]+)/", &component[1..component.len()-1])[..]);
            } else {
                rv.push_str(&format!("{}/", component)[..]);
            }
        }
        //Remove the trailing /
        rv.pop();
        rv.push_str("$");
        //This will fail at runtime if the regexp is invalid
        Regex::new(&rv[..]).unwrap()
    }
}

pub struct WebDriverHttpApi<U: WebDriverExtensionRoute> {
    routes: Vec<(Method, RequestMatcher<U>)>,
}

impl <U: WebDriverExtensionRoute> WebDriverHttpApi<U> {
    pub fn new(extension_routes: &[(Method, &str, U)]) -> WebDriverHttpApi<U> {
        let mut rv = WebDriverHttpApi::<U> {
            routes: vec![],
        };
        debug!("Creating routes");
        for &(ref method, ref url, ref match_type) in standard_routes::<U>().iter() {
            rv.add(method.clone(), *url, (*match_type).clone());
        };
        for &(ref method, ref url, ref extension_route) in extension_routes.iter() {
            rv.add(method.clone(), *url, Route::Extension(extension_route.clone()));
        };
        rv
    }

    fn add(&mut self, method: Method, path: &str, match_type: Route<U>) {
        let http_matcher = RequestMatcher::new(method.clone(), path, match_type);
        self.routes.push((method, http_matcher));
    }

    pub fn decode_request(&self, method: Method, path: &str, body: &str) -> WebDriverResult<WebDriverMessage<U>> {
        let mut error = ErrorStatus::UnknownPath;
        for &(ref match_method, ref matcher) in self.routes.iter() {
            if method == *match_method {
                let (method_match, captures) = matcher.get_match(method.clone(), path);
                if captures.is_some() {
                    if method_match {
                        return WebDriverMessage::from_http(matcher.match_type.clone(),
                                                           &captures.unwrap(),
                                                           body,
                                                           method == Post)
                    } else {
                        error = ErrorStatus::UnknownMethod;
                    }
                }
            }
        }
        Err(WebDriverError::new(error,
                                format!("{} {} did not match a known command", method, path)))
    }
}
<|endoftext|>


<commit_before>#[allow(non_camel_case_types)];

pub use self::utmpx::{DEFAULT_FILE,USER_PROCESS,c_utmp};
#[cfg(target_os = "linux")]
mod utmpx {
    use std::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmp";

    pub static UT_LINESIZE: uint = 32;
    pub static UT_NAMESIZE: uint = 32;
    pub static UT_IDSIZE: uint = 4;
    pub static UT_HOSTSIZE: uint = 256;

    pub static EMPTY: libc::c_short = 0;
    pub static RUN_LVL: libc::c_short = 1;
    pub static BOOT_TIME: libc::c_short = 2;
    pub static NEW_TIME: libc::c_short = 3;
    pub static OLD_TIME: libc::c_short = 4;
    pub static INIT_PROCESS: libc::c_short = 5;
    pub static LOGIN_PROCESS: libc::c_short = 6;
    pub static USER_PROCESS: libc::c_short = 7;
    pub static DEAD_PROCESS: libc::c_short = 8;
    pub static ACCOUNTING: libc::c_short = 9;

    pub struct c_exit_status {
        e_termination: libc::c_short,
        e_exit: libc::c_short,
    }

    pub struct c_utmp {
        ut_type: libc::c_short,
        ut_pid: libc::pid_t,
        ut_line: [libc::c_char, ..UT_LINESIZE],
        ut_id: [libc::c_char, ..UT_IDSIZE],

        ut_user: [libc::c_char, ..UT_NAMESIZE],
        ut_host: [libc::c_char, ..UT_HOSTSIZE],
        ut_exit: c_exit_status,
        ut_session: libc::c_long,
        ut_tv: libc::timeval,

        ut_addr_v6: [libc::int32_t, ..4],
        __unused: [libc::c_char, ..20],
    }
}

#[cfg(target_os = "macos")]
mod utmpx {
    use std::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";

    pub static UT_LINESIZE: uint = 32;
    pub static UT_NAMESIZE: uint = 256;
    pub static UT_IDSIZE: uint = 4;
    pub static UT_HOSTSIZE: uint = 256;

    pub static EMPTY: libc::c_short = 0;
    pub static RUN_LVL: libc::c_short = 1;
    pub static BOOT_TIME: libc::c_short = 2;
    pub static OLD_TIME: libc::c_short = 3;
    pub static NEW_TIME: libc::c_short = 4;
    pub static INIT_PROCESS: libc::c_short = 5;
    pub static LOGIN_PROCESS: libc::c_short = 6;
    pub static USER_PROCESS: libc::c_short = 7;
    pub static DEAD_PROCESS: libc::c_short = 8;
    pub static ACCOUNTING: libc::c_short = 9;

    pub struct c_exit_status {
        e_termination: libc::c_short,
        e_exit: libc::c_short,
    }

    pub struct c_utmp {
        ut_user: [libc::c_char, ..UT_NAMESIZE],
        ut_id: [libc::c_char, ..UT_IDSIZE],
        ut_line: [libc::c_char, ..UT_LINESIZE],
        ut_pid: libc::pid_t,
        ut_type: libc::c_short,
        ut_tv: libc::timeval,
        ut_host: [libc::c_char, ..UT_HOSTSIZE],
        __unused: [libc::c_char, ..16]
    }
}

<commit_msg>Silence dead code warnings for Constants<commit_after>#[allow(non_camel_case_types)];
#[allow(dead_code)];

pub use self::utmpx::{DEFAULT_FILE,USER_PROCESS,c_utmp};
#[cfg(target_os = "linux")]
mod utmpx {
    use std::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmp";

    pub static UT_LINESIZE: uint = 32;
    pub static UT_NAMESIZE: uint = 32;
    pub static UT_IDSIZE: uint = 4;
    pub static UT_HOSTSIZE: uint = 256;

    pub static EMPTY: libc::c_short = 0;
    pub static RUN_LVL: libc::c_short = 1;
    pub static BOOT_TIME: libc::c_short = 2;
    pub static NEW_TIME: libc::c_short = 3;
    pub static OLD_TIME: libc::c_short = 4;
    pub static INIT_PROCESS: libc::c_short = 5;
    pub static LOGIN_PROCESS: libc::c_short = 6;
    pub static USER_PROCESS: libc::c_short = 7;
    pub static DEAD_PROCESS: libc::c_short = 8;
    pub static ACCOUNTING: libc::c_short = 9;

    pub struct c_exit_status {
        e_termination: libc::c_short,
        e_exit: libc::c_short,
    }

    pub struct c_utmp {
        ut_type: libc::c_short,
        ut_pid: libc::pid_t,
        ut_line: [libc::c_char, ..UT_LINESIZE],
        ut_id: [libc::c_char, ..UT_IDSIZE],

        ut_user: [libc::c_char, ..UT_NAMESIZE],
        ut_host: [libc::c_char, ..UT_HOSTSIZE],
        ut_exit: c_exit_status,
        ut_session: libc::c_long,
        ut_tv: libc::timeval,

        ut_addr_v6: [libc::int32_t, ..4],
        __unused: [libc::c_char, ..20],
    }
}

#[cfg(target_os = "macos")]
mod utmpx {
    use std::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";

    pub static UT_LINESIZE: uint = 32;
    pub static UT_NAMESIZE: uint = 256;
    pub static UT_IDSIZE: uint = 4;
    pub static UT_HOSTSIZE: uint = 256;

    pub static EMPTY: libc::c_short = 0;
    pub static RUN_LVL: libc::c_short = 1;
    pub static BOOT_TIME: libc::c_short = 2;
    pub static OLD_TIME: libc::c_short = 3;
    pub static NEW_TIME: libc::c_short = 4;
    pub static INIT_PROCESS: libc::c_short = 5;
    pub static LOGIN_PROCESS: libc::c_short = 6;
    pub static USER_PROCESS: libc::c_short = 7;
    pub static DEAD_PROCESS: libc::c_short = 8;
    pub static ACCOUNTING: libc::c_short = 9;

    pub struct c_exit_status {
        e_termination: libc::c_short,
        e_exit: libc::c_short,
    }

    pub struct c_utmp {
        ut_user: [libc::c_char, ..UT_NAMESIZE],
        ut_id: [libc::c_char, ..UT_IDSIZE],
        ut_line: [libc::c_char, ..UT_LINESIZE],
        ut_pid: libc::pid_t,
        ut_type: libc::c_short,
        ut_tv: libc::timeval,
        ut_host: [libc::c_char, ..UT_HOSTSIZE],
        __unused: [libc::c_char, ..16]
    }
}

<|endoftext|>


<commit_before>use crate::{
    buffer::Buffer, channels::Channels, connection_status::ConnectionState, frames::Frames,
    internal_rpc::InternalRPC, thread::ThreadHandle, waker::Waker, Configuration, ConnectionStatus,
    Error, PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker as MioWaker};
use std::{
    collections::VecDeque,
    io::{self, Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection_status: ConnectionStatus,
    configuration: Configuration,
    channels: Channels,
    internal_rpc: InternalRPC,
    frames: Frames,
    connection_io_loop_handle: ThreadHandle,
    waker: Waker,
    socket: T,
    status: Status,
    poll: Poll,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    #[allow(clippy::too_many_arguments)]
    pub(crate) fn new(
        connection_status: ConnectionStatus,
        configuration: Configuration,
        channels: Channels,
        internal_rpc: InternalRPC,
        frames: Frames,
        connection_io_loop_handle: ThreadHandle,
        waker: Waker,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        waker.set_waker(MioWaker::new(poll.registry(), WAKER)?);
        let frame_size = std::cmp::max(8192, configuration.frame_max() as usize);
        let mut inner = Self {
            connection_status,
            configuration,
            channels,
            internal_rpc,
            frames,
            connection_io_loop_handle,
            waker,
            socket,
            status: Status::Initial,
            poll,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) {
        if self.status != Status::Setup && self.connection_status.connected() {
            let frame_max = self.configuration.frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.configuration.heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
    }

    fn has_data(&self) -> bool {
        self.frames.has_pending()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection_status.blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        (self.status == Status::Initial
            || self.connection_status.connected()
            || self.connection_status.closing())
            && self.status != Status::Stop
            && !self.connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection_io_loop_handle.clone().register(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.critical_error(err)?;
                        }
                    }
                    Ok(())
                })?,
        );
        waker.wake()
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll_internal_rpc(&self) -> Result<()> {
        self.internal_rpc.poll(&self.channels)
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                if event.is_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                self.can_read = true;
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup();
        self.poll(events)?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection_status.closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.handle_frames()?;
            if self.should_heartbeat() {
                self.channels.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        self.poll_internal_rpc()
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection_status.errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        self.poll_internal_rpc()
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let Some(resolver) = self.connection_status.connection_resolver() {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.channels.set_connection_error(error.clone())?;
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.socket.flush()?;

        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            }

            self.socket.flush()?;
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        self.poll_internal_rpc()
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection_status.state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer.read_from(&mut self.socket).map(|sz| {
                    trace!("read {} bytes", sz);
                    self.receive_buffer.fill(sz);
                })?;
                self.poll_internal_rpc()
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.frames.pop(self.channels.flow()) {
            trace!("will write to buffer: {}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => self.serialized_frames.push_back((sz, resolver)),
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.frames.retry((next_msg, resolver));
                            self.send_continue()?;
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            self.critical_error(Error::SerialisationError(Arc::new(e)))?;
                        }
                    }
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn handle_frames(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.parse()? {
                self.channels.handle_frame(frame)?;
            }
        }
        self.poll_internal_rpc()
    }

    fn parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.parsing_context()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed);
                Ok(Some(f))
            }
            Err(e) => {
                if !e.is_incomplete() {
                    error!("parse error: {:?}", e);
                    self.critical_error(Error::ParsingError(e))?;
                }
                Ok(None)
            }
        }
    }
}
<commit_msg>IoLoop: handle error before read/write closed<commit_after>use crate::{
    buffer::Buffer, channels::Channels, connection_status::ConnectionState, frames::Frames,
    internal_rpc::InternalRPC, thread::ThreadHandle, waker::Waker, Configuration, ConnectionStatus,
    Error, PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker as MioWaker};
use std::{
    collections::VecDeque,
    io::{self, Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection_status: ConnectionStatus,
    configuration: Configuration,
    channels: Channels,
    internal_rpc: InternalRPC,
    frames: Frames,
    connection_io_loop_handle: ThreadHandle,
    waker: Waker,
    socket: T,
    status: Status,
    poll: Poll,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    #[allow(clippy::too_many_arguments)]
    pub(crate) fn new(
        connection_status: ConnectionStatus,
        configuration: Configuration,
        channels: Channels,
        internal_rpc: InternalRPC,
        frames: Frames,
        connection_io_loop_handle: ThreadHandle,
        waker: Waker,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        waker.set_waker(MioWaker::new(poll.registry(), WAKER)?);
        let frame_size = std::cmp::max(8192, configuration.frame_max() as usize);
        let mut inner = Self {
            connection_status,
            configuration,
            channels,
            internal_rpc,
            frames,
            connection_io_loop_handle,
            waker,
            socket,
            status: Status::Initial,
            poll,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) {
        if self.status != Status::Setup && self.connection_status.connected() {
            let frame_max = self.configuration.frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.configuration.heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
    }

    fn has_data(&self) -> bool {
        self.frames.has_pending()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection_status.blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        (self.status == Status::Initial
            || self.connection_status.connected()
            || self.connection_status.closing())
            && self.status != Status::Stop
            && !self.connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection_io_loop_handle.clone().register(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.critical_error(err)?;
                        }
                    }
                    Ok(())
                })?,
        );
        waker.wake()
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll_internal_rpc(&self) -> Result<()> {
        self.internal_rpc.poll(&self.channels)
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                self.can_read = true;
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup();
        self.poll(events)?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection_status.closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.handle_frames()?;
            if self.should_heartbeat() {
                self.channels.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        self.poll_internal_rpc()
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection_status.errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        self.poll_internal_rpc()
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let Some(resolver) = self.connection_status.connection_resolver() {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.channels.set_connection_error(error.clone())?;
        for (_, resolver) in std::mem::take(&mut self.serialized_frames) {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.socket.flush()?;

        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            }

            self.socket.flush()?;
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        self.poll_internal_rpc()
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection_status.state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer.read_from(&mut self.socket).map(|sz| {
                    trace!("read {} bytes", sz);
                    self.receive_buffer.fill(sz);
                })?;
                self.poll_internal_rpc()
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.frames.pop(self.channels.flow()) {
            trace!("will write to buffer: {}", next_msg);
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => self.serialized_frames.push_back((sz, resolver)),
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.frames.retry((next_msg, resolver));
                            self.send_continue()?;
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            self.critical_error(Error::SerialisationError(Arc::new(e)))?;
                        }
                    }
                }
            }
        }
        self.poll_internal_rpc()
    }

    fn handle_frames(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.parse()? {
                self.channels.handle_frame(frame)?;
            }
        }
        self.poll_internal_rpc()
    }

    fn parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.parsing_context()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed);
                Ok(Some(f))
            }
            Err(e) => {
                if !e.is_incomplete() {
                    error!("parse error: {:?}", e);
                    self.critical_error(Error::ParsingError(e))?;
                }
                Ok(None)
            }
        }
    }
}
<|endoftext|>