use async_trait::async_trait;
use tracing::error;
use super::super::tokens::{ErrorToken, Tokens};
use super::common::TokenParser;
use crate::{core::TdsResult, io::packet_reader::TdsPacketReader};
use crate::{io::token_stream::ParserContext, token::tokens::TokenType};
#[derive(Default)]
pub(crate) struct ErrorTokenParser {
}
#[async_trait]
impl<T> TokenParser<T> for ErrorTokenParser
where
T: TdsPacketReader + Send + Sync,
{
async fn parse(&self, reader: &mut T, _context: &ParserContext) -> TdsResult<Tokens> {
error!(
"Parsing Error token with type: 0x{:02X}",
TokenType::Error as u8
);
let _ = reader.read_uint16().await?;
let number = reader.read_uint32().await?;
let state = reader.read_byte().await?;
let severity = reader.read_byte().await?;
let message = reader.read_varchar_u16_length().await?.unwrap_or_default();
error!("Error message: {:?}", message);
let server_name = reader.read_varchar_u8_length().await?;
let proc_name = reader.read_varchar_u8_length().await?;
let line_number = reader.read_uint32().await?;
Ok(Tokens::from(ErrorToken {
number,
state,
severity,
message,
server_name,
proc_name,
line_number,
}))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::message::messages::PacketType;
use crate::test_packet_support::{TestPacketBuilder, create_network_transport_with_data};
fn encode_utf16_string(s: &str) -> Vec<u8> {
let utf16_units: Vec<u16> = s.encode_utf16().collect();
let mut bytes = Vec::with_capacity(utf16_units.len() * 2);
for unit in utf16_units {
bytes.push((unit & 0xFF) as u8);
bytes.push((unit >> 8) as u8);
}
bytes
}
#[tokio::test]
async fn test_parse_error_token_basic() {
let mut builder = TestPacketBuilder::new(PacketType::PreLogin);
let message = "Invalid object name";
let server_name = "TestServer";
let proc_name = "";
let message_bytes = encode_utf16_string(message);
let server_bytes = encode_utf16_string(server_name);
let proc_bytes = encode_utf16_string(proc_name);
let length = 4 + 1 + 1 + 2 + message_bytes.len() + 1 + server_bytes.len() + 1 + proc_bytes.len() + 4;
builder.append_u16(length as u16); builder.append_u32(208); builder.append_byte(1); builder.append_byte(16);
builder.append_u16(message.len() as u16);
builder.append_bytes(&message_bytes);
builder.append_byte(server_name.len() as u8);
builder.append_bytes(&server_bytes);
builder.append_byte(proc_name.len() as u8);
builder.append_bytes(&proc_bytes);
builder.append_u32(1);
let mut packet_reader = create_network_transport_with_data(&builder.build());
let parser = ErrorTokenParser::default();
let context = ParserContext::default();
let result = parser.parse(&mut packet_reader, &context).await.unwrap();
match result {
Tokens::Error(token) => {
assert_eq!(token.number, 208);
assert_eq!(token.state, 1);
assert_eq!(token.severity, 16);
assert_eq!(token.message, message);
assert_eq!(token.server_name, server_name);
assert_eq!(token.proc_name, proc_name);
assert_eq!(token.line_number, 1);
}
_ => panic!("Expected Error token"),
}
}
#[tokio::test]
async fn test_parse_error_token_with_proc() {
let mut builder = TestPacketBuilder::new(PacketType::PreLogin);
let message = "Error in stored procedure";
let server_name = "ProdServer";
let proc_name = "sp_GetUserData";
let message_bytes = encode_utf16_string(message);
let server_bytes = encode_utf16_string(server_name);
let proc_bytes = encode_utf16_string(proc_name);
let length =
4 + 1 + 1 + 2 + message_bytes.len() + 1 + server_bytes.len() + 1 + proc_bytes.len() + 4;
builder.append_u16(length as u16);
builder.append_u32(50000); builder.append_byte(2);
builder.append_byte(17);
builder.append_u16(message.len() as u16);
builder.append_bytes(&message_bytes);
builder.append_byte(server_name.len() as u8);
builder.append_bytes(&server_bytes);
builder.append_byte(proc_name.len() as u8);
builder.append_bytes(&proc_bytes);
builder.append_u32(123);
let mut packet_reader = create_network_transport_with_data(&builder.build());
let parser = ErrorTokenParser::default();
let context = ParserContext::default();
let result = parser.parse(&mut packet_reader, &context).await.unwrap();
match result {
Tokens::Error(token) => {
assert_eq!(token.number, 50000);
assert_eq!(token.state, 2);
assert_eq!(token.severity, 17);
assert_eq!(token.message, message);
assert_eq!(token.server_name, server_name);
assert_eq!(token.proc_name, proc_name);
assert_eq!(token.line_number, 123);
}
_ => panic!("Expected Error token"),
}
}
#[tokio::test]
async fn test_parse_error_token_constraint_violation() {
let mut builder = TestPacketBuilder::new(PacketType::PreLogin);
let message = "Violation of PRIMARY KEY constraint";
let server_name = "DB1";
let proc_name = "";
let message_bytes = encode_utf16_string(message);
let server_bytes = encode_utf16_string(server_name);
let proc_bytes = encode_utf16_string(proc_name);
let length =
4 + 1 + 1 + 2 + message_bytes.len() + 1 + server_bytes.len() + 1 + proc_bytes.len() + 4;
builder.append_u16(length as u16);
builder.append_u32(2627); builder.append_byte(1);
builder.append_byte(14);
builder.append_u16(message.len() as u16);
builder.append_bytes(&message_bytes);
builder.append_byte(server_name.len() as u8);
builder.append_bytes(&server_bytes);
builder.append_byte(0); builder.append_u32(5);
let mut packet_reader = create_network_transport_with_data(&builder.build());
let parser = ErrorTokenParser::default();
let context = ParserContext::default();
let result = parser.parse(&mut packet_reader, &context).await.unwrap();
match result {
Tokens::Error(token) => {
assert_eq!(token.number, 2627);
assert_eq!(token.severity, 14);
assert_eq!(token.message, message);
assert_eq!(token.proc_name, "");
}
_ => panic!("Expected Error token"),
}
}
#[tokio::test]
async fn test_parse_error_token_fatal() {
let mut builder = TestPacketBuilder::new(PacketType::PreLogin);
let message = "Fatal error";
let server_name = "SQL";
let proc_name = "";
let message_bytes = encode_utf16_string(message);
let server_bytes = encode_utf16_string(server_name);
let proc_bytes = encode_utf16_string(proc_name);
let length =
4 + 1 + 1 + 2 + message_bytes.len() + 1 + server_bytes.len() + 1 + proc_bytes.len() + 4;
builder.append_u16(length as u16);
builder.append_u32(9999);
builder.append_byte(1);
builder.append_byte(25);
builder.append_u16(message.len() as u16);
builder.append_bytes(&message_bytes);
builder.append_byte(server_name.len() as u8);
builder.append_bytes(&server_bytes);
builder.append_byte(0);
builder.append_u32(0);
let mut packet_reader = create_network_transport_with_data(&builder.build());
let parser = ErrorTokenParser::default();
let context = ParserContext::default();
let result = parser.parse(&mut packet_reader, &context).await.unwrap();
match result {
Tokens::Error(token) => {
assert_eq!(token.severity, 25);
assert_eq!(token.message, message);
}
_ => panic!("Expected Error token"),
}
}
}