Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ internet-packet = { version = "0.2.3", features = ["smoltcp"] }
data-encoding = "2.8.0"
hickory-resolver = "0.24.4"
socket2 = "0.5.8"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"
rmp-serde = "1.1"

[patch.crates-io]
# tokio = { path = "../tokio/tokio" }
Expand Down
6 changes: 4 additions & 2 deletions mitmproxy-rs/mitmproxy_rs/contentviews.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ from typing import ClassVar, final
class Contentview:
name: ClassVar[str]

def deserialize(self, data: bytes) -> str:
def prettify(self, data: bytes) -> str:
pass

@final
class InteractiveContentview(Contentview):
def serialize(self, data: str) -> bytes:
def reencode(self, data: str) -> bytes:
pass

hex_dump: Contentview
hex_stream: InteractiveContentview
msgpack: InteractiveContentview

__all__ = [
"Contentview",
"InteractiveContentview",
"hex_dump",
"hex_stream",
"msgpack",
]
8 changes: 4 additions & 4 deletions mitmproxy-rs/src/contentview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ impl Contentview {
}

/// Pretty-print an (encoded) message.
pub fn deserialize<'py>(&self, data: Vec<u8>) -> Result<String> {
self.0.deserialize(data).map_err(|e| anyhow!("{e}"))
pub fn prettify<'py>(&self, data: Vec<u8>) -> Result<String> {
self.0.prettify(data).map_err(|e| anyhow!("{e}"))
}

fn __repr__(&self) -> PyResult<String> {
Expand Down Expand Up @@ -52,8 +52,8 @@ impl InteractiveContentview {

#[pymethods]
impl InteractiveContentview {
pub fn serialize<'py>(&self, data: String) -> Result<Vec<u8>> {
self.0.serialize(data).map_err(|e| anyhow!("{e}"))
pub fn reencode<'py>(&self, data: String) -> Result<Vec<u8>> {
self.0.reencode(data).map_err(|e| anyhow!("{e}"))
}

fn __repr__(self_: PyRef<'_, Self>) -> PyResult<String> {
Expand Down
3 changes: 2 additions & 1 deletion mitmproxy-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,13 @@ mod mitmproxy_rs {
use crate::contentview::Contentview;
#[pymodule_export]
use crate::contentview::InteractiveContentview;
use mitmproxy::contentviews::{HexDump, HexStream};
use mitmproxy::contentviews::{HexDump, HexStream, MsgPack};

#[pymodule_init]
fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_contentview(&HexDump)?;
m.add_interactive_contentview(&HexStream)?;
m.add_interactive_contentview(&MsgPack)?;
Ok(())
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/contentviews/hex_dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ impl Prettify for HexDump {
"Hex Dump"
}

fn deserialize(&self, data: Vec<u8>) -> Result<String, PrettifyError> {
fn prettify(&self, data: Vec<u8>) -> Result<String, PrettifyError> {
Ok(format!(
"{:?}",
data.hex_conf(HexConfig {
Expand All @@ -31,7 +31,7 @@ mod tests {
#[test]
fn test_hexdump_deserialize() {
let data = b"abcd".to_vec();
let result = HexDump.deserialize(data).unwrap();
let result = HexDump.prettify(data).unwrap();
assert_eq!(
result,
"0000: 61 62 63 64 abcd"
Expand All @@ -41,7 +41,7 @@ mod tests {
#[test]
fn test_hexdump_deserialize_empty() {
let data = vec![];
let result = HexDump.deserialize(data).unwrap();
let result = HexDump.prettify(data).unwrap();
assert_eq!(result, "");
}
}
10 changes: 5 additions & 5 deletions src/contentviews/hex_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ impl Prettify for HexStream {
"Hex Stream"
}

fn deserialize(&self, data: Vec<u8>) -> Result<String, PrettifyError> {
fn prettify(&self, data: Vec<u8>) -> Result<String, PrettifyError> {
Ok(data
.hex_conf(HexConfig {
title: false,
Expand All @@ -25,7 +25,7 @@ impl Prettify for HexStream {
}

impl Reencode for HexStream {
fn serialize(&self, data: String) -> anyhow::Result<Vec<u8>, ReencodeError> {
fn reencode(&self, data: String) -> anyhow::Result<Vec<u8>, ReencodeError> {
(0..data.len())
.step_by(2)
.map(|i| u8::from_str_radix(&data[i..i + 2], 16))
Expand All @@ -41,21 +41,21 @@ mod tests {
#[test]
fn test_hexstream_deserialize() {
let data = b"foo".to_vec();
let result = HexStream.deserialize(data).unwrap();
let result = HexStream.prettify(data).unwrap();
assert_eq!(result, "666f6f");
}

#[test]
fn test_hexstream_deserialize_empty() {
let data = vec![];
let result = HexStream.deserialize(data).unwrap();
let result = HexStream.prettify(data).unwrap();
assert_eq!(result, "");
}

#[test]
fn test_hexstream_serialize() {
let data = "666f6f".to_string();
let result = HexStream.serialize(data).unwrap();
let result = HexStream.reencode(data).unwrap();
assert_eq!(result, b"foo");
}
}
6 changes: 4 additions & 2 deletions src/contentviews/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod hex_dump;
mod hex_stream;
mod msgpack;

use anyhow::Result;
use std::fmt::{Display, Formatter};

pub use hex_dump::HexDump;
pub use hex_stream::HexStream;
pub use msgpack::MsgPack;

#[derive(Debug)]
pub enum ReencodeError {
Expand Down Expand Up @@ -44,9 +46,9 @@ pub trait Prettify: Send + Sync {
self.name().to_lowercase().replace(" ", "_")
}

fn deserialize(&self, data: Vec<u8>) -> Result<String, PrettifyError>;
fn prettify(&self, data: Vec<u8>) -> Result<String, PrettifyError>;
}

pub trait Reencode: Send + Sync {
fn serialize(&self, data: String) -> Result<Vec<u8>, ReencodeError>;
fn reencode(&self, data: String) -> Result<Vec<u8>, ReencodeError>;
}
127 changes: 127 additions & 0 deletions src/contentviews/msgpack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use crate::contentviews::{Prettify, PrettifyError, Reencode, ReencodeError};
use rmp_serde::{decode, encode};
use serde_yaml;

pub struct MsgPack;

impl Prettify for MsgPack {
fn name(&self) -> &'static str {
"MsgPack"
}

fn prettify(&self, data: Vec<u8>) -> Result<String, PrettifyError> {
// Deserialize MsgPack to a serde_yaml::Value
let value: serde_yaml::Value = decode::from_slice(&data)
.map_err(|e| PrettifyError::Generic(format!("Failed to deserialize MsgPack: {}", e)))?;

// Convert the Value to prettified YAML
serde_yaml::to_string(&value)
.map_err(|e| PrettifyError::Generic(format!("Failed to convert to YAML: {}", e)))
}
}

impl Reencode for MsgPack {
fn reencode(&self, data: String) -> anyhow::Result<Vec<u8>, ReencodeError> {
// Parse the YAML string to a serde_yaml::Value
let value: serde_yaml::Value = serde_yaml::from_str(&data)
.map_err(|e| ReencodeError::InvalidFormat(format!("Invalid YAML: {}", e)))?;

// Serialize the Value to MsgPack
let mut buf = Vec::new();
encode::write_named(&mut buf, &value).map_err(|e| {
ReencodeError::InvalidFormat(format!("Failed to encode to MsgPack: {}", e))
})?;

Ok(buf)
}
}

#[cfg(test)]
mod tests {
use super::*;

// Hardcoded MsgPack data for a simple object:
// {
// "name": "John Doe",
// "age": 30,
// "tags": ["developer", "rust"]
// }
const TEST_MSGPACK: &[u8] = &[
0x83, // map with 3 elements
0xa4, 0x6e, 0x61, 0x6d, 0x65, // "name"
0xa8, 0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x44, 0x6f, 0x65, // "John Doe"
0xa3, 0x61, 0x67, 0x65, // "age"
0x1e, // 30
0xa4, 0x74, 0x61, 0x67, 0x73, // "tags"
0x92, // array with 2 elements
0xa9, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x72, // "developer"
0xa4, 0x72, 0x75, 0x73, 0x74, // "rust"
];

// Expected YAML representation
const TEST_YAML: &str = r#"name: John Doe
age: 30
tags:
- developer
- rust
"#;

#[test]
fn test_msgpack_deserialize() {
let result = MsgPack.prettify(TEST_MSGPACK.to_vec()).unwrap();
assert_eq!(result, TEST_YAML);
}

#[test]
fn test_msgpack_serialize() {
let yaml_data = TEST_YAML.to_string();

let result = MsgPack.reencode(yaml_data).unwrap();

// Verify the MsgPack data contains the expected values
let value: serde_yaml::Value = decode::from_slice(&result).unwrap();

if let serde_yaml::Value::Mapping(map) = value {
assert_eq!(
map.get(serde_yaml::Value::String("name".to_string())),
Some(&serde_yaml::Value::String("John Doe".to_string()))
);

assert_eq!(
map.get(serde_yaml::Value::String("age".to_string())),
Some(&serde_yaml::Value::Number(serde_yaml::Number::from(30)))
);

if let Some(serde_yaml::Value::Sequence(tags)) =
map.get(serde_yaml::Value::String("tags".to_string()))
{
assert_eq!(tags.len(), 2);
assert_eq!(tags[0], serde_yaml::Value::String("developer".to_string()));
assert_eq!(tags[1], serde_yaml::Value::String("rust".to_string()));
} else {
panic!("tags is not a sequence");
}
} else {
panic!("value is not a mapping");
}
}

#[test]
fn test_msgpack_roundtrip() {
// Start with the hardcoded MsgPack data
let msgpack_data = TEST_MSGPACK.to_vec();

// Deserialize to YAML
let yaml_result = MsgPack.prettify(msgpack_data).unwrap();

// Serialize back to MsgPack
let result = MsgPack.reencode(yaml_result).unwrap();

// Deserialize both the original and the result to Values for comparison
let original_value: serde_yaml::Value = decode::from_slice(TEST_MSGPACK).unwrap();
let result_value: serde_yaml::Value = decode::from_slice(&result).unwrap();

// Compare the values
assert_eq!(original_value, result_value);
}
}