Add capacity error types

pull/168/head
WiredSound 4 years ago
parent aaebb432f0
commit 0b34bee94f
  1. 81
      src/error.rs
  2. 4
      src/handshake/machine.rs
  3. 21
      src/protocol/frame/mod.rs
  4. 9
      src/protocol/message.rs
  5. 19
      src/protocol/mod.rs

@ -1,6 +1,6 @@
//! Error handling.
use std::{borrow::Cow, error::Error as ErrorTrait, fmt, io, result, str, string};
use std::{error::Error as ErrorTrait, fmt, io, result, str, string};
use crate::protocol::{frame::coding::Data, Message};
use http::Response;
@ -46,7 +46,7 @@ pub enum Error {
/// - When reading: buffer capacity exhausted.
/// - When writing: your message is bigger than the configured max message size
/// (64MB by default).
Capacity(Cow<'static, str>),
Capacity(CapacityErrorType),
/// Protocol violation.
Protocol(ProtocolErrorType),
/// Message send queue full.
@ -146,38 +146,39 @@ impl From<tls::Error> for Error {
impl From<httparse::Error> for Error {
fn from(err: httparse::Error) -> Self {
match err {
httparse::Error::TooManyHeaders => Error::Capacity("Too many headers".into()),
httparse::Error::TooManyHeaders => Error::Capacity(CapacityErrorType::TooManyHeaders),
e => Error::Protocol(ProtocolErrorType::HttparseError(e)),
}
}
}
/// Indicates the specific type/cause of URL error.
#[derive(Debug, PartialEq, Eq)]
pub enum UrlErrorType {
/// TLS is used despite not being compiled with the TLS feature enabled.
TlsFeatureNotEnabled,
/// The URL does not include a host name.
NoHostName,
/// Failed to connect with this URL.
UnableToConnect(String),
/// Unsupported URL scheme used (only `ws://` or `wss://` may be used).
UnsupportedUrlScheme,
/// The URL host name, though included, is empty.
EmptyHostName,
/// The URL does not include a path/query.
NoPathOrQuery,
/// Indicates the specific type/cause of a capacity error.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CapacityErrorType {
/// Too many headers provided (see [`httparse::Error::TooManyHeaders`]).
TooManyHeaders,
/// Received header is too long.
HeaderTooLong,
/// Message is bigger than the maximum allowed size.
MessageTooLong {
/// The size of the message.
size: usize,
/// The maximum allowed message size.
max_size: usize,
},
/// TCP buffer is full.
TcpBufferFull,
}
impl fmt::Display for UrlErrorType {
impl fmt::Display for CapacityErrorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
UrlErrorType::TlsFeatureNotEnabled => write!(f, "TLS support not compiled in"),
UrlErrorType::NoHostName => write!(f, "No host name in the URL"),
UrlErrorType::UnableToConnect(uri) => write!(f, "Unable to connect to {}", uri),
UrlErrorType::UnsupportedUrlScheme => write!(f, "URL scheme not supported"),
UrlErrorType::EmptyHostName => write!(f, "URL contains empty host name"),
UrlErrorType::NoPathOrQuery => write!(f, "No path/query in URL"),
CapacityErrorType::TooManyHeaders => write!(f, "Too many headers"),
CapacityErrorType::HeaderTooLong => write!(f, "Header too long"),
CapacityErrorType::MessageTooLong { size, max_size } => {
write!(f, "Message too long: {} > {}", size, max_size)
}
CapacityErrorType::TcpBufferFull => write!(f, "Incoming TCP buffer is full"),
}
}
}
@ -302,3 +303,33 @@ impl fmt::Display for ProtocolErrorType {
}
}
}
/// Indicates the specific type/cause of URL error.
#[derive(Debug, PartialEq, Eq)]
pub enum UrlErrorType {
/// TLS is used despite not being compiled with the TLS feature enabled.
TlsFeatureNotEnabled,
/// The URL does not include a host name.
NoHostName,
/// Failed to connect with this URL.
UnableToConnect(String),
/// Unsupported URL scheme used (only `ws://` or `wss://` may be used).
UnsupportedUrlScheme,
/// The URL host name, though included, is empty.
EmptyHostName,
/// The URL does not include a path/query.
NoPathOrQuery,
}
impl fmt::Display for UrlErrorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
UrlErrorType::TlsFeatureNotEnabled => write!(f, "TLS support not compiled in"),
UrlErrorType::NoHostName => write!(f, "No host name in the URL"),
UrlErrorType::UnableToConnect(uri) => write!(f, "Unable to connect to {}", uri),
UrlErrorType::UnsupportedUrlScheme => write!(f, "URL scheme not supported"),
UrlErrorType::EmptyHostName => write!(f, "URL contains empty host name"),
UrlErrorType::NoPathOrQuery => write!(f, "No path/query in URL"),
}
}
}

@ -3,7 +3,7 @@ use log::*;
use std::io::{Cursor, Read, Write};
use crate::{
error::{Error, ProtocolErrorType, Result},
error::{CapacityErrorType, Error, ProtocolErrorType, Result},
util::NonBlockingResult,
};
use input_buffer::{InputBuffer, MIN_READ};
@ -46,7 +46,7 @@ impl<Stream: Read + Write> HandshakeMachine<Stream> {
let read = buf
.prepare_reserve(MIN_READ)
.with_limit(usize::max_value()) // TODO limit size
.map_err(|_| Error::Capacity("Header too long".into()))?
.map_err(|_| Error::Capacity(CapacityErrorType::HeaderTooLong))?
.read_from(&mut self.stream)
.no_block()?;
match read {

@ -8,7 +8,7 @@ mod mask;
pub use self::frame::{CloseFrame, Frame, FrameHeader};
use crate::error::{Error, Result};
use crate::error::{CapacityErrorType, Error, Result};
use input_buffer::{InputBuffer, MIN_READ};
use log::*;
use std::io::{Error as IoError, ErrorKind as IoErrorKind, Read, Write};
@ -133,9 +133,10 @@ impl FrameCodec {
// Enforce frame size limit early and make sure `length`
// is not too big (fits into `usize`).
if length > max_size as u64 {
return Err(Error::Capacity(
format!("Message length too big: {} > {}", length, max_size).into(),
));
return Err(Error::Capacity(CapacityErrorType::MessageTooLong {
size: length as usize,
max_size,
}));
}
let input_size = cursor.get_ref().len() as u64 - cursor.position();
@ -155,7 +156,7 @@ impl FrameCodec {
.in_buffer
.prepare_reserve(MIN_READ)
.with_limit(usize::max_value())
.map_err(|_| Error::Capacity("Incoming TCP buffer is full".into()))?
.map_err(|_| Error::Capacity(CapacityErrorType::TcpBufferFull))?
.read_from(stream)?;
if size == 0 {
trace!("no frame received");
@ -206,6 +207,8 @@ impl FrameCodec {
#[cfg(test)]
mod tests {
use crate::error::{CapacityErrorType, Error};
use super::{Frame, FrameSocket};
use std::io::Cursor;
@ -266,9 +269,9 @@ mod tests {
fn size_limit_hit() {
let raw = Cursor::new(vec![0x82, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]);
let mut sock = FrameSocket::new(raw);
assert_eq!(
sock.read_frame(Some(5)).unwrap_err().to_string(),
"Space limit exceeded: Message length too big: 7 > 5"
);
match sock.read_frame(Some(5)) {
Err(Error::Capacity(CapacityErrorType::MessageTooLong { size: 7, max_size: 5 })) => {}
_ => panic!(),
}
}
}

@ -6,7 +6,7 @@ use std::{
};
use super::frame::CloseFrame;
use crate::error::{Error, Result};
use crate::error::{CapacityErrorType, Error, Result};
mod string_collect {
use utf8::DecodeError;
@ -122,9 +122,10 @@ impl IncompleteMessage {
let portion_size = tail.as_ref().len();
// Be careful about integer overflows here.
if my_size > max_size || portion_size > max_size - my_size {
return Err(Error::Capacity(
format!("Message too big: {} + {} > {}", my_size, portion_size, max_size).into(),
));
return Err(Error::Capacity(CapacityErrorType::MessageTooLong {
size: my_size + portion_size,
max_size,
}));
}
match self.collector {

@ -669,6 +669,7 @@ impl<T> CheckConnectionReset for Result<T> {
#[cfg(test)]
mod tests {
use super::{Message, Role, WebSocket, WebSocketConfig};
use crate::error::{CapacityErrorType, Error};
use std::{io, io::Cursor};
@ -711,10 +712,11 @@ mod tests {
]);
let limit = WebSocketConfig { max_message_size: Some(10), ..WebSocketConfig::default() };
let mut socket = WebSocket::from_raw_socket(WriteMoc(incoming), Role::Client, Some(limit));
assert_eq!(
socket.read_message().unwrap_err().to_string(),
"Space limit exceeded: Message too big: 7 + 6 > 10"
);
match socket.read_message() {
Err(Error::Capacity(CapacityErrorType::MessageTooLong { size: 13, max_size: 10 })) => {}
_ => panic!(),
}
}
#[test]
@ -722,9 +724,10 @@ mod tests {
let incoming = Cursor::new(vec![0x82, 0x03, 0x01, 0x02, 0x03]);
let limit = WebSocketConfig { max_message_size: Some(2), ..WebSocketConfig::default() };
let mut socket = WebSocket::from_raw_socket(WriteMoc(incoming), Role::Client, Some(limit));
assert_eq!(
socket.read_message().unwrap_err().to_string(),
"Space limit exceeded: Message too big: 0 + 3 > 2"
);
match socket.read_message() {
Err(Error::Capacity(CapacityErrorType::MessageTooLong { size: 3, max_size: 2 })) => {}
_ => panic!(),
}
}
}

Loading…
Cancel
Save