Rev 1289 | Blame | Compare with Previous | Last modification | View Log | RSS feed
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
// GENERAL DESIGN
//
// Methods which are not running in the main application thread
// are not allowed no interact with GUI elemenents.
// FIXME:
// - add soap validation
// - icons for all items in the tree
// - use pool of threads?
// - do not store intermediate info, just row packets and the parsed fragments to display
// - make the text fragment store switchable
// - set locks during log writing (?)
// - show '100 (Continue)' response info
namespace TCPproxy
{
public class MainForm : Form
{
#region constants and settings
private const int RECENT_LENGTH = 20;
public const string REGISTRY_KEY = @"Software\Anatoli Klassen\TCPproxy";
public const string REGISTRY_RECENT_SUBKEY = "Recent Listenings";
public const byte LOG_TYPE_BIN = 1;
public const string LOG_BIN_HEADER = "TCPproxy 1.0\n";
#endregion constants and settings
#region private fields
private ListenForm listenForm = new ListenForm();
private TcpListener tcpListener = null;
private LogMessages logMessages = null;
private Hashtable treeNodes = new Hashtable();
private ArrayList recentItems = new ArrayList();
private int listenPort;
private string resendHost;
private int resendPort;
private TcpShowMode tcpShowMode = TcpShowMode.ByDirection;
private bool autoExpand = true;
private bool clearing = false;
private string defaultCaption;
#endregion private fields
#region web forms fields
private System.ComponentModel.IContainer components;
private SaveFileDialog saveLogDialog;
private StatusBarPanel connectionStatusBar;
private MenuItem selectAllmenuItem;
private MenuItem copyMenuItem;
private ContextMenu viewContextMenu;
private MenuItem closeConnectionMenuItem;
private ImageList saveButtonImageList;
private StatusBar statusBar;
private ContextMenu messagesContextMenu;
private ImageList treeImageList;
private MenuItem wordWrapMenuItem;
private MainMenu mainMenu;
private MenuItem fileMenu;
private MenuItem loadBinLogMenuItem;
private MenuItem saveBinLogMenuItem;
private MenuItem menuSeparator1;
private MenuItem exitMenuItem;
private MenuItem viewMenu;
private MenuItem clearMainMenuItem;
private MenuItem messagesMenu;
private MenuItem saveLogMenuItem;
private MenuItem saveTcoLogMenuItem;
private MenuItem saveHttpLogMenuItem;
private MenuItem saveXmlLogMenuItem;
private MenuItem menuSeparator2;
private MenuItem allMessagesMenuItem;
private MenuItem importantMessagesMenuItem;
private MenuItem infoMessagesMenuItem;
private MenuItem menuSeparator3;
private MenuItem tcpShowByDirectionMenuItem;
private MenuItem tcpShowByTimeMenuItem;
private MenuItem menuSeparator4;
private MenuItem autoExpandMainMenuItem;
private MenuItem wordWrapMainMenuItem;
private MenuItem helpMenu;
private Panel panel1;
private Panel panel3;
private Panel panel4;
private ViewControl messagesBox;
private Splitter splitter2;
private ListBox logBox;
private Splitter splitter1;
private TreeView messageView;
private MenuItem startMenuItem;
private MenuItem stopMenuItem;
private MenuItem menuSeparator5;
private MenuItem recentListeningMenu;
private MenuItem recentListeningNoItem;
private SaveFileDialog saveBinLogDialog;
private OpenFileDialog loadBinLogDialog;
private MenuItem autoExpandMenuItem;
private MenuItem aboutMenuItem;
#endregion web forms fields
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.components=new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources=new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.wordWrapMenuItem=new System.Windows.Forms.MenuItem();
this.treeImageList=new System.Windows.Forms.ImageList(this.components);
this.messagesContextMenu=new System.Windows.Forms.ContextMenu();
this.selectAllmenuItem=new System.Windows.Forms.MenuItem();
this.copyMenuItem=new System.Windows.Forms.MenuItem();
this.statusBar=new System.Windows.Forms.StatusBar();
this.connectionStatusBar=new System.Windows.Forms.StatusBarPanel();
this.saveButtonImageList=new System.Windows.Forms.ImageList(this.components);
this.closeConnectionMenuItem=new System.Windows.Forms.MenuItem();
this.viewContextMenu=new System.Windows.Forms.ContextMenu();
this.autoExpandMenuItem=new System.Windows.Forms.MenuItem();
this.saveLogDialog=new System.Windows.Forms.SaveFileDialog();
this.mainMenu=new System.Windows.Forms.MainMenu(this.components);
this.fileMenu=new System.Windows.Forms.MenuItem();
this.startMenuItem=new System.Windows.Forms.MenuItem();
this.stopMenuItem=new System.Windows.Forms.MenuItem();
this.recentListeningMenu=new System.Windows.Forms.MenuItem();
this.recentListeningNoItem=new System.Windows.Forms.MenuItem();
this.menuSeparator5=new System.Windows.Forms.MenuItem();
this.loadBinLogMenuItem=new System.Windows.Forms.MenuItem();
this.saveBinLogMenuItem=new System.Windows.Forms.MenuItem();
this.menuSeparator1=new System.Windows.Forms.MenuItem();
this.saveLogMenuItem=new System.Windows.Forms.MenuItem();
this.saveTcoLogMenuItem=new System.Windows.Forms.MenuItem();
this.saveHttpLogMenuItem=new System.Windows.Forms.MenuItem();
this.saveXmlLogMenuItem=new System.Windows.Forms.MenuItem();
this.menuSeparator2=new System.Windows.Forms.MenuItem();
this.exitMenuItem=new System.Windows.Forms.MenuItem();
this.viewMenu=new System.Windows.Forms.MenuItem();
this.clearMainMenuItem=new System.Windows.Forms.MenuItem();
this.messagesMenu=new System.Windows.Forms.MenuItem();
this.allMessagesMenuItem=new System.Windows.Forms.MenuItem();
this.infoMessagesMenuItem=new System.Windows.Forms.MenuItem();
this.importantMessagesMenuItem=new System.Windows.Forms.MenuItem();
this.menuSeparator3=new System.Windows.Forms.MenuItem();
this.tcpShowByDirectionMenuItem=new System.Windows.Forms.MenuItem();
this.tcpShowByTimeMenuItem=new System.Windows.Forms.MenuItem();
this.menuSeparator4=new System.Windows.Forms.MenuItem();
this.autoExpandMainMenuItem=new System.Windows.Forms.MenuItem();
this.wordWrapMainMenuItem=new System.Windows.Forms.MenuItem();
this.helpMenu=new System.Windows.Forms.MenuItem();
this.aboutMenuItem=new System.Windows.Forms.MenuItem();
this.panel1=new System.Windows.Forms.Panel();
this.panel3=new System.Windows.Forms.Panel();
this.panel4=new System.Windows.Forms.Panel();
this.splitter2=new System.Windows.Forms.Splitter();
this.logBox=new System.Windows.Forms.ListBox();
this.splitter1=new System.Windows.Forms.Splitter();
this.messageView=new System.Windows.Forms.TreeView();
this.saveBinLogDialog=new System.Windows.Forms.SaveFileDialog();
this.loadBinLogDialog=new System.Windows.Forms.OpenFileDialog();
this.messagesBox=new TCPproxy.ViewControl();
((System.ComponentModel.ISupportInitialize)(this.connectionStatusBar)).BeginInit();
this.panel1.SuspendLayout();
this.panel3.SuspendLayout();
this.panel4.SuspendLayout();
this.SuspendLayout();
//
// wordWrapMenuItem
//
this.wordWrapMenuItem.Index=2;
this.wordWrapMenuItem.Text="Word &Wrap";
this.wordWrapMenuItem.Click+=new System.EventHandler(this.wordWrapMenuItem_Click);
//
// treeImageList
//
this.treeImageList.ImageStream=((System.Windows.Forms.ImageListStreamer)(resources.GetObject("treeImageList.ImageStream")));
this.treeImageList.TransparentColor=System.Drawing.Color.Magenta;
this.treeImageList.Images.SetKeyName(0, "");
this.treeImageList.Images.SetKeyName(1, "");
this.treeImageList.Images.SetKeyName(2, "");
//
// messagesContextMenu
//
this.messagesContextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.selectAllmenuItem,
this.copyMenuItem,
this.wordWrapMenuItem});
//
// selectAllmenuItem
//
this.selectAllmenuItem.Index=0;
this.selectAllmenuItem.Shortcut=System.Windows.Forms.Shortcut.CtrlA;
this.selectAllmenuItem.Text="Select &All";
this.selectAllmenuItem.Click+=new System.EventHandler(this.selectAllMenuItem_Click);
//
// copyMenuItem
//
this.copyMenuItem.Index=1;
this.copyMenuItem.Shortcut=System.Windows.Forms.Shortcut.CtrlC;
this.copyMenuItem.Text="&Copy";
this.copyMenuItem.Click+=new System.EventHandler(this.copyMenuItem_Click);
//
// statusBar
//
this.statusBar.Location=new System.Drawing.Point(0, 279);
this.statusBar.Name="statusBar";
this.statusBar.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] {
this.connectionStatusBar});
this.statusBar.ShowPanels=true;
this.statusBar.Size=new System.Drawing.Size(780, 22);
this.statusBar.TabIndex=0;
//
// connectionStatusBar
//
this.connectionStatusBar.AutoSize=System.Windows.Forms.StatusBarPanelAutoSize.Spring;
this.connectionStatusBar.Name="connectionStatusBar";
this.connectionStatusBar.Width=764;
//
// saveButtonImageList
//
this.saveButtonImageList.ImageStream=((System.Windows.Forms.ImageListStreamer)(resources.GetObject("saveButtonImageList.ImageStream")));
this.saveButtonImageList.TransparentColor=System.Drawing.Color.Magenta;
this.saveButtonImageList.Images.SetKeyName(0, "");
//
// closeConnectionMenuItem
//
this.closeConnectionMenuItem.Index=0;
this.closeConnectionMenuItem.Text="&Close connection";
this.closeConnectionMenuItem.Click+=new System.EventHandler(this.closeConnectionMenuItem_Click);
//
// viewContextMenu
//
this.viewContextMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.closeConnectionMenuItem,
this.autoExpandMenuItem});
//
// autoExpandMenuItem
//
this.autoExpandMenuItem.Index=1;
this.autoExpandMenuItem.Text="Auto E&xpand";
this.autoExpandMenuItem.Click+=new System.EventHandler(this.autoExpandMenuItem_Click);
//
// saveLogDialog
//
this.saveLogDialog.DefaultExt="txt";
this.saveLogDialog.Filter="Text Files (*.txt)|*.txt|All Files|*.*";
this.saveLogDialog.Title="Save Log";
//
// mainMenu
//
this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.fileMenu,
this.viewMenu,
this.helpMenu});
//
// fileMenu
//
this.fileMenu.Index=0;
this.fileMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.startMenuItem,
this.stopMenuItem,
this.recentListeningMenu,
this.menuSeparator5,
this.loadBinLogMenuItem,
this.saveBinLogMenuItem,
this.menuSeparator1,
this.saveLogMenuItem,
this.saveTcoLogMenuItem,
this.saveHttpLogMenuItem,
this.saveXmlLogMenuItem,
this.menuSeparator2,
this.exitMenuItem});
this.fileMenu.Text="&File";
//
// startMenuItem
//
this.startMenuItem.Index=0;
this.startMenuItem.Text="&Start...";
this.startMenuItem.Click+=new System.EventHandler(this.startMenuItem_Click);
//
// stopMenuItem
//
this.stopMenuItem.Enabled=false;
this.stopMenuItem.Index=1;
this.stopMenuItem.Text="S&top";
this.stopMenuItem.Click+=new System.EventHandler(this.stopMenuItem_Click);
//
// recentListeningMenu
//
this.recentListeningMenu.Index=2;
this.recentListeningMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.recentListeningNoItem});
this.recentListeningMenu.Text="&Recent Listenings";
//
// recentListeningNoItem
//
this.recentListeningNoItem.Enabled=false;
this.recentListeningNoItem.Index=0;
this.recentListeningNoItem.Text="(no items)";
//
// menuSeparator5
//
this.menuSeparator5.Index=3;
this.menuSeparator5.Text="-";
//
// loadBinLogMenuItem
//
this.loadBinLogMenuItem.Index=4;
this.loadBinLogMenuItem.Text="&Load Bin Log...";
this.loadBinLogMenuItem.Click+=new System.EventHandler(this.loadBinLogMenuItem_Click);
//
// saveBinLogMenuItem
//
this.saveBinLogMenuItem.Index=5;
this.saveBinLogMenuItem.Text="&Save Bin Log...";
this.saveBinLogMenuItem.Click+=new System.EventHandler(this.saveBinLogMenuItem_Click);
//
// menuSeparator1
//
this.menuSeparator1.Index=6;
this.menuSeparator1.Text="-";
//
// saveLogMenuItem
//
this.saveLogMenuItem.Index=7;
this.saveLogMenuItem.Text="Save Log Messa&ges...";
this.saveLogMenuItem.Click+=new System.EventHandler(this.saveLogMenuItem_Click);
//
// saveTcoLogMenuItem
//
this.saveTcoLogMenuItem.Index=8;
this.saveTcoLogMenuItem.Text="Save T&CP Log...";
this.saveTcoLogMenuItem.Click+=new System.EventHandler(this.saveTcpMenuItem_Click);
//
// saveHttpLogMenuItem
//
this.saveHttpLogMenuItem.Index=9;
this.saveHttpLogMenuItem.Text="Save Htt&p Log...";
this.saveHttpLogMenuItem.Click+=new System.EventHandler(this.saveHttpMenuItem_Click);
//
// saveXmlLogMenuItem
//
this.saveXmlLogMenuItem.Index=10;
this.saveXmlLogMenuItem.Text="Save X&ML Log...";
this.saveXmlLogMenuItem.Click+=new System.EventHandler(this.saveXmlMenuItem_Click);
//
// menuSeparator2
//
this.menuSeparator2.Index=11;
this.menuSeparator2.Text="-";
//
// exitMenuItem
//
this.exitMenuItem.Index=12;
this.exitMenuItem.Text="E&xit";
//
// viewMenu
//
this.viewMenu.Index=1;
this.viewMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.clearMainMenuItem,
this.messagesMenu,
this.menuSeparator3,
this.tcpShowByDirectionMenuItem,
this.tcpShowByTimeMenuItem,
this.menuSeparator4,
this.autoExpandMainMenuItem,
this.wordWrapMainMenuItem});
this.viewMenu.Text="&View";
//
// clearMainMenuItem
//
this.clearMainMenuItem.Index=0;
this.clearMainMenuItem.Text="&Clear";
this.clearMainMenuItem.Click+=new System.EventHandler(this.clearMenuItem_Click);
//
// messagesMenu
//
this.messagesMenu.Index=1;
this.messagesMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.allMessagesMenuItem,
this.infoMessagesMenuItem,
this.importantMessagesMenuItem});
this.messagesMenu.Text="&Messages";
//
// allMessagesMenuItem
//
this.allMessagesMenuItem.Checked=true;
this.allMessagesMenuItem.Index=0;
this.allMessagesMenuItem.Text="&All";
this.allMessagesMenuItem.Click+=new System.EventHandler(this.messagesMenuItem_Click);
//
// infoMessagesMenuItem
//
this.infoMessagesMenuItem.Index=1;
this.infoMessagesMenuItem.Text="&Info";
this.infoMessagesMenuItem.Click+=new System.EventHandler(this.messagesMenuItem_Click);
//
// importantMessagesMenuItem
//
this.importantMessagesMenuItem.Index=2;
this.importantMessagesMenuItem.Text="I&mportant";
this.importantMessagesMenuItem.Click+=new System.EventHandler(this.messagesMenuItem_Click);
//
// menuSeparator3
//
this.menuSeparator3.Index=2;
this.menuSeparator3.Text="-";
//
// tcpShowByDirectionMenuItem
//
this.tcpShowByDirectionMenuItem.Checked=true;
this.tcpShowByDirectionMenuItem.Index=3;
this.tcpShowByDirectionMenuItem.Text="TCP Show by &Direction";
this.tcpShowByDirectionMenuItem.Click+=new System.EventHandler(this.tcpShowByDirectionMenuItem_Click);
//
// tcpShowByTimeMenuItem
//
this.tcpShowByTimeMenuItem.Index=4;
this.tcpShowByTimeMenuItem.Text="TCP Show by &Time";
this.tcpShowByTimeMenuItem.Click+=new System.EventHandler(this.tcpShowByTimeMenuItem_Click);
//
// menuSeparator4
//
this.menuSeparator4.Index=5;
this.menuSeparator4.Text="-";
//
// autoExpandMainMenuItem
//
this.autoExpandMainMenuItem.Index=6;
this.autoExpandMainMenuItem.Text="Auto E&xpand";
this.autoExpandMainMenuItem.Click+=new System.EventHandler(this.autoExpandMenuItem_Click);
//
// wordWrapMainMenuItem
//
this.wordWrapMainMenuItem.Index=7;
this.wordWrapMainMenuItem.Text="Word &Wrap";
this.wordWrapMainMenuItem.Click+=new System.EventHandler(this.wordWrapMenuItem_Click);
//
// helpMenu
//
this.helpMenu.Index=2;
this.helpMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.aboutMenuItem});
this.helpMenu.Text="&Help";
//
// aboutMenuItem
//
this.aboutMenuItem.Index=0;
this.aboutMenuItem.Text="&About...";
this.aboutMenuItem.Click+=new System.EventHandler(this.aboutMenuItem_Click);
//
// panel1
//
this.panel1.Controls.Add(this.panel3);
this.panel1.Dock=System.Windows.Forms.DockStyle.Fill;
this.panel1.Location=new System.Drawing.Point(0, 0);
this.panel1.Name="panel1";
this.panel1.Size=new System.Drawing.Size(780, 279);
this.panel1.TabIndex=11;
//
// panel3
//
this.panel3.Controls.Add(this.panel4);
this.panel3.Controls.Add(this.splitter1);
this.panel3.Controls.Add(this.messageView);
this.panel3.Dock=System.Windows.Forms.DockStyle.Fill;
this.panel3.Location=new System.Drawing.Point(0, 0);
this.panel3.Name="panel3";
this.panel3.Size=new System.Drawing.Size(780, 279);
this.panel3.TabIndex=5;
//
// panel4
//
this.panel4.Controls.Add(this.messagesBox);
this.panel4.Controls.Add(this.splitter2);
this.panel4.Controls.Add(this.logBox);
this.panel4.Dock=System.Windows.Forms.DockStyle.Fill;
this.panel4.Location=new System.Drawing.Point(163, 0);
this.panel4.Name="panel4";
this.panel4.Size=new System.Drawing.Size(617, 279);
this.panel4.TabIndex=13;
//
// splitter2
//
this.splitter2.Dock=System.Windows.Forms.DockStyle.Bottom;
this.splitter2.Location=new System.Drawing.Point(0, 208);
this.splitter2.Name="splitter2";
this.splitter2.Size=new System.Drawing.Size(617, 3);
this.splitter2.TabIndex=9;
this.splitter2.TabStop=false;
//
// logBox
//
this.logBox.Dock=System.Windows.Forms.DockStyle.Bottom;
this.logBox.Font=new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.logBox.HorizontalScrollbar=true;
this.logBox.ItemHeight=16;
this.logBox.Location=new System.Drawing.Point(0, 211);
this.logBox.Name="logBox";
this.logBox.ScrollAlwaysVisible=true;
this.logBox.Size=new System.Drawing.Size(617, 68);
this.logBox.TabIndex=8;
//
// splitter1
//
this.splitter1.Location=new System.Drawing.Point(160, 0);
this.splitter1.Name="splitter1";
this.splitter1.Size=new System.Drawing.Size(3, 279);
this.splitter1.TabIndex=12;
this.splitter1.TabStop=false;
//
// messageView
//
this.messageView.ContextMenu=this.viewContextMenu;
this.messageView.Dock=System.Windows.Forms.DockStyle.Left;
this.messageView.HideSelection=false;
this.messageView.ImageIndex=0;
this.messageView.ImageList=this.treeImageList;
this.messageView.Location=new System.Drawing.Point(0, 0);
this.messageView.Name="messageView";
this.messageView.SelectedImageIndex=0;
this.messageView.Size=new System.Drawing.Size(160, 279);
this.messageView.TabIndex=11;
this.messageView.AfterSelect+=new System.Windows.Forms.TreeViewEventHandler(this.messageView_AfterSelect);
this.messageView.MouseDown+=new System.Windows.Forms.MouseEventHandler(this.messageView_MouseDown);
this.messageView.BeforeSelect+=new System.Windows.Forms.TreeViewCancelEventHandler(this.messageView_BeforeSelect);
//
// saveBinLogDialog
//
this.saveBinLogDialog.DefaultExt="tcp";
this.saveBinLogDialog.Filter="TCP Logs (*.bin)|*.bin|All Files|*.*";
this.saveBinLogDialog.Title="Save Binary Log";
//
// loadBinLogDialog
//
this.loadBinLogDialog.FileName="openFileDialog1";
this.loadBinLogDialog.Filter="TCP Logs (*.bin)|*.bin|All Files|*.*";
this.loadBinLogDialog.Title="Load Binary Log";
//
// messagesBox
//
this.messagesBox.ContextMenu=this.messagesContextMenu;
this.messagesBox.Dock=System.Windows.Forms.DockStyle.Fill;
this.messagesBox.Font=new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.messagesBox.Location=new System.Drawing.Point(0, 0);
this.messagesBox.Name="messagesBox";
this.messagesBox.Size=new System.Drawing.Size(617, 208);
this.messagesBox.TabIndex=7;
this.messagesBox.WordWrap=true;
//
// MainForm
//
this.AutoScaleBaseSize=new System.Drawing.Size(5, 13);
this.ClientSize=new System.Drawing.Size(780, 301);
this.Controls.Add(this.panel1);
this.Controls.Add(this.statusBar);
this.Menu=this.mainMenu;
this.MinimumSize=new System.Drawing.Size(400, 200);
this.Name="MainForm";
this.StartPosition=System.Windows.Forms.FormStartPosition.Manual;
this.Text="TCPproxy";
((System.ComponentModel.ISupportInitialize)(this.connectionStatusBar)).EndInit();
this.panel1.ResumeLayout(false);
this.panel3.ResumeLayout(false);
this.panel4.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
#region windows forms methods
public MainForm()
{
InitializeComponent();
logMessages = new LogMessages(logBox);
try {
LoadFromRegistry();
LoadRecentItemsFromRegistry();
}
catch(Exception) {}
// update visual elements
UpdateMessagesMenuItems();
if(tcpShowMode == TcpShowMode.ByDirection) {
tcpShowByDirectionMenuItem.Checked = true;
tcpShowByTimeMenuItem.Checked = false;
}
else {
tcpShowByDirectionMenuItem.Checked = false;
tcpShowByTimeMenuItem.Checked = true;
}
autoExpandMenuItem.Checked = autoExpand;
autoExpandMainMenuItem.Checked = autoExpand;
wordWrapMenuItem.Checked = messagesBox.WordWrap;
wordWrapMainMenuItem.Checked = messagesBox.WordWrap;
// save default values
defaultCaption = this.Text;
messagesBox.BeginUpdate();
messagesBox.Clear();
for(int i = 0; i < 50; ++i) {
messagesBox.AppendNewLine();
messagesBox.AppendText(String.Format("Line {0} 12345689 12345689 12345689 12345689 12345689 12345689 12345689 12345689 12345689 12345689 12345689",
i+1), Color.Black, Color.Transparent, false, false, 0, 0);
}
messagesBox.EndUpdate();
}
protected override void Dispose(bool disposing)
{
clearing = true;
if(tcpListener != null) {
tcpListener.StopListening(); // stop listening
tcpListener.CancelAll(); // cancel all open connections
}
// save settings
SaveToRegistry();
SaveRecentItemsToRegistry();
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
ThreadDebugger.PrintStatus();
}
[STAThread]
static void Main()
{
Application.Run(new MainForm());
}
private void startMenuItem_Click(object sender, System.EventArgs e)
{
IPAddress resendIp;
if(!listenForm.Execute(this,
ref listenPort, ref resendHost, out resendIp, ref resendPort)) return;
StartListening(listenPort, resendIp, resendPort);
}
private void stopMenuItem_Click(object sender, System.EventArgs e)
{
StopListening();
}
private void clearMenuItem_Click(object sender, System.EventArgs e)
{
ClearAll();
}
private void selectAllMenuItem_Click(object sender, System.EventArgs e)
{
messagesBox.SelectAll();
}
private void copyMenuItem_Click(object sender, System.EventArgs e)
{
string sel = messagesBox.SelectedText;
if(sel != null) Clipboard.SetDataObject(sel);
}
private void wordWrapMenuItem_Click(object sender, System.EventArgs e)
{
messagesBox.WordWrap = !messagesBox.WordWrap;
wordWrapMenuItem.Checked = messagesBox.WordWrap;
wordWrapMainMenuItem.Checked = messagesBox.WordWrap;
}
private void autoExpandMenuItem_Click(object sender, System.EventArgs e)
{
autoExpand = !autoExpand;
autoExpandMenuItem.Checked = autoExpand;
autoExpandMainMenuItem.Checked = autoExpand;
}
private void aboutMenuItem_Click(object sender, EventArgs e)
{
(new AboutForm()).ShowDialog(this);
}
private void messageView_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
messageView.Tag = null; // clear the right-click item
if(messageView.SelectedNode == null) return;
object tag = messageView.SelectedNode.Tag;
if(tag is TreeNodeData)
{
TreeNodeData data = (TreeNodeData)tag;
data.SaveViewState();
}
}
private void messageView_AfterSelect(object sender, TreeViewEventArgs e)
{
if(messageView.SelectedNode == null) return;
object tag = messageView.SelectedNode.Tag;
if(tag is TreeNodeData)
{
TreeNodeData data = (TreeNodeData)tag;
data.Show();
}
}
private void closeConnectionMenuItem_Click(object sender, System.EventArgs e)
{
TreeNode node;
if(messageView.Tag != null) {
node = messageView.GetNodeAt((Point)messageView.Tag);
}
else {
node = messageView.SelectedNode;
}
if(node != null)
{
object tag = node.Tag;
if(tag is TcpNodeData)
CloseTcpConnection(((TcpNodeData)tag).Tcp);
else if(tag is TcpNodeData)
CloseTcpConnection(((TcpNodeData)node.Parent.Tag).Tcp);
else if(tag is XmlNodeData)
CloseTcpConnection(((TcpNodeData)node.Parent.Parent.Tag).Tcp);
}
}
private void messageView_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button == MouseButtons.Right) {
messageView.Tag = new Point(e.X, e.Y); // save mouse click coord
}
}
private void tcpShowByDirectionMenuItem_Click(object sender, System.EventArgs e)
{
tcpShowMode = TcpShowMode.ByDirection;
tcpShowByDirectionMenuItem.Checked = true;
tcpShowByTimeMenuItem.Checked = false;
TreeNode node;
if(messageView.Tag != null) {
node = messageView.GetNodeAt((Point)messageView.Tag);
}
else {
node = messageView.SelectedNode;
}
if(node != null)
{
object tag = node.Tag;
if(tag is TcpNodeData)
UpdateTcpNodeInternal(((TcpNodeData)tag).Tcp);
}
}
private void tcpShowByTimeMenuItem_Click(object sender, System.EventArgs e)
{
tcpShowMode = TcpShowMode.ByTime;
tcpShowByDirectionMenuItem.Checked = false;
tcpShowByTimeMenuItem.Checked = true;
if(messageView.SelectedNode == null) return;
TreeNode node;
if(messageView.Tag != null) {
node = messageView.GetNodeAt((Point)messageView.Tag);
}
else {
node = messageView.SelectedNode;
}
if(node != null)
{
object tag = node.Tag;
if(tag is TcpNodeData)
UpdateTcpNodeInternal(((TcpNodeData)tag).Tcp);
}
}
private void saveLogMenuItem_Click(object sender, System.EventArgs e)
{
if(saveLogDialog.ShowDialog() == DialogResult.OK) {
try {
SaveLog(saveLogDialog.FileName);
}
catch(Exception ex) {
MessageBox.Show("Cannot save log to file " + saveLogDialog.FileName
+ ":\n" + ex.Message, "TCPproxy",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void saveTcpMenuItem_Click(object sender, System.EventArgs e)
{
if(saveLogDialog.ShowDialog() == DialogResult.OK) {
try {
SaveTcp(saveLogDialog.FileName);
}
catch(Exception ex) {
MessageBox.Show("Cannot save TCP log to file " + saveLogDialog.FileName
+ ":\n" + ex.Message, "TCPproxy",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void saveHttpMenuItem_Click(object sender, System.EventArgs e)
{
if(saveLogDialog.ShowDialog() == DialogResult.OK) {
try {
SaveHttp(saveLogDialog.FileName);
}
catch(Exception ex) {
MessageBox.Show("Cannot save HTTP log to file " + saveLogDialog.FileName
+ ":\n" + ex.Message, "TCPproxy",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void saveXmlMenuItem_Click(object sender, System.EventArgs e)
{
if(saveLogDialog.ShowDialog() == DialogResult.OK) {
try {
SaveXml(saveLogDialog.FileName);
}
catch(Exception ex) {
MessageBox.Show("Cannot save XML log to file " + saveLogDialog.FileName
+ ":\n" + ex.Message, "TCPproxy",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void saveBinLogMenuItem_Click(object sender, EventArgs e)
{
if(saveBinLogDialog.ShowDialog() == DialogResult.OK) {
try {
SaveBinLog(saveBinLogDialog.FileName);
}
catch(Exception ex) {
MessageBox.Show("Cannot save binary log to file " + saveBinLogDialog.FileName
+ ":\n" + ex.Message, "TCPproxy",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void loadBinLogMenuItem_Click(object sender, EventArgs e)
{
if(loadBinLogDialog.ShowDialog() == DialogResult.OK) {
try {
LoadBinLog(loadBinLogDialog.FileName);
}
catch(Exception ex) {
MessageBox.Show("Cannot load binary log from file " + loadBinLogDialog.FileName
+ ":\n" + ex.Message, "TCPproxy",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void messagesMenuItem_Click(object sender, EventArgs e)
{
if(sender == importantMessagesMenuItem)
logMessages.Level = LogLevel.Important;
else if(sender == infoMessagesMenuItem)
logMessages.Level = LogLevel.Info;
else
logMessages.Level = LogLevel.Debug;
UpdateMessagesMenuItems();
}
private void recentMenuItem_Click(object sender, EventArgs e)
{
MenuItem menuItem = (MenuItem)sender;
RecentItem recentItem = (RecentItem)recentItems[recentItems.Count - menuItem.Index - 1];
IPAddress resendIp;
this.listenPort = recentItem.ListenPort;
this.resendHost = recentItem.ResendHost;
this.resendPort = recentItem.ResendPort;
try
{
resendIp = HostUtils.ResendHostToIp(resendHost);
}
catch(Exception ex)
{
MessageBox.Show("Cannot get host IP: " + ex.Message, "TCPproxy",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
StartListening(listenPort, resendIp, resendPort);
}
#endregion windows forms methods
#region core methods
private LogLevel ParseLogLevel(string str)
{
if(str == "Important")
return LogLevel.Important;
else if(str == "Info")
return LogLevel.Info;
else
return LogLevel.Debug;
}
private void LoadFromRegistry()
{
Microsoft.Win32.RegistryKey subkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
REGISTRY_KEY);
if(subkey == null) return;
listenPort = (int)subkey.GetValue("Listen Port", 0);
resendHost = (string)subkey.GetValue("Resend Host", "");
resendPort = (int)subkey.GetValue("Resend Port", 0);
logMessages.Level = ParseLogLevel((string)subkey.GetValue("Messages Level", ""));
autoExpand = (int)subkey.GetValue("Auto Expand", 1) == 1;
messagesBox.WordWrap = (int)subkey.GetValue("Word Wrap", 1) == 1;
object tcpShowModeStr = (object)subkey.GetValue("Tcp Show Mode", TcpShowMode.ByDirection);
tcpShowMode = (tcpShowModeStr as string) == "ByDirection"
? TcpShowMode.ByDirection : TcpShowMode.ByTime;
int winTop = (int)subkey.GetValue("Window.Top", -1);
int winLeft = (int)subkey.GetValue("Window.Left", -1);
if(winTop < 0 || winLeft < 0
|| winTop >= SystemInformation.WorkingArea.Height || winLeft >= SystemInformation.WorkingArea.Width)
{
this.StartPosition = FormStartPosition.WindowsDefaultBounds;
}
else {
this.Top = winTop;
this.Left = winLeft;
this.ClientSize = new Size(
(int)subkey.GetValue("Window.Width", this.ClientSize.Width),
(int)subkey.GetValue("Window.Hight", this.ClientSize.Height));
this.messageView.Width
= (int)subkey.GetValue("Splitter.Left", this.messageView.Width);
this.logBox.Height
= (int)subkey.GetValue("Splitter.Bottom", this.logBox.Height);
}
}
private void LoadRecentItemsFromRegistry()
{
Microsoft.Win32.RegistryKey subkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(
REGISTRY_KEY + @"\" + REGISTRY_RECENT_SUBKEY);
if(subkey == null) return;
foreach(string name in subkey.GetValueNames()) {
if(name == "") continue;
AddRecentItem(RecentItem.LoadFromRegistry((string)subkey.GetValue(name, "")));
}
}
private void SaveToRegistry()
{
Microsoft.Win32.RegistryKey subkey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(
REGISTRY_KEY);
subkey.SetValue("Listen Port", listenPort);
subkey.SetValue("Resend Host", resendHost == null ? "" : resendHost);
subkey.SetValue("Resend Port", resendPort);
subkey.SetValue("Messages Level", logMessages.Level);
subkey.SetValue("Tcp Show Mode", tcpShowMode);
subkey.SetValue("Auto Expand", autoExpand ? 1 : 0);
subkey.SetValue("Word Wrap", messagesBox.WordWrap ? 1 : 0);
subkey.SetValue("Window.Top", this.Top);
subkey.SetValue("Window.Left", this.Left);
subkey.SetValue("Window.Hight", this.ClientSize.Height);
subkey.SetValue("Window.Width", this.ClientSize.Width);
subkey.SetValue("Splitter.Left", this.messageView.Width);
subkey.SetValue("Splitter.Bottom", this.logBox.Height);
}
private void SaveRecentItemsToRegistry()
{
Microsoft.Win32.RegistryKey subkey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(
REGISTRY_KEY + @"\" + REGISTRY_RECENT_SUBKEY);
// load existing from registry
ArrayList old = new ArrayList();
foreach(string name in subkey.GetValueNames()) {
if(name == "") continue;
old.Add(RecentItem.LoadFromRegistry((string)subkey.GetValue(name, "")));
}
// merge - for the case another program instance has changed the list
foreach(RecentItem item in old) {
int existingIdx = recentItems.IndexOf(item);
if(existingIdx >= 0)
((RecentItem)recentItems[existingIdx]).UpdateTimestamp(item);
else
recentItems.Add(item);
}
recentItems.Sort();
if(recentItems.Count > 0) // take tail
recentItems = recentItems.GetRange(Math.Max(0, recentItems.Count - RECENT_LENGTH),
Math.Min(recentItems.Count, RECENT_LENGTH));
int count = 0;
foreach(RecentItem item in recentItems) {
subkey.SetValue(string.Format("{0:0000}", count++), item.SaveToRegistry());
}
}
private void UpdateMessagesMenuItems()
{
switch(logMessages.Level) {
case LogLevel.Critical:
case LogLevel.Error:
case LogLevel.Warning:
case LogLevel.Important:
importantMessagesMenuItem.Checked = true;
infoMessagesMenuItem.Checked = false;
allMessagesMenuItem.Checked = false;
break;
case LogLevel.Info:
importantMessagesMenuItem.Checked = false;
infoMessagesMenuItem.Checked = true;
allMessagesMenuItem.Checked = false;
break;
case LogLevel.Debug:
importantMessagesMenuItem.Checked = false;
infoMessagesMenuItem.Checked = false;
allMessagesMenuItem.Checked = true;
break;
}
}
private void AddRecentItem(int listenPort, string resendHost, int resendPort)
{
RecentItem recentItem = new RecentItem(listenPort, resendHost, resendPort);
recentItem.UpdateTimestamp();
AddRecentItem(recentItem);
}
private void AddRecentItem(RecentItem recentItem)
{
int existingIdx = recentItems.IndexOf(recentItem);
if(existingIdx >= 0) {
this.recentListeningMenu.MenuItems.RemoveAt(recentItems.Count - existingIdx - 1);
recentItems.RemoveAt(existingIdx);
}
if(recentItems.Count == 0 && this.recentListeningMenu.MenuItems.Count == 1)
this.recentListeningMenu.MenuItems.RemoveAt(0);
recentItems.Add(recentItem);
MenuItem menuItem = new MenuItem();
this.recentListeningMenu.MenuItems.Add(0, menuItem);
menuItem.Text = string.Format("&1 {0} to {1}:{2}",
recentItem.ListenPort, recentItem.ResendHost, recentItem.ResendPort);
menuItem.Click += new System.EventHandler(recentMenuItem_Click);
// check overflow
if(recentItems.Count > RECENT_LENGTH) {
this.recentListeningMenu.MenuItems.RemoveAt(recentItems.Count - 1);
recentItems.RemoveAt(0);
}
// update hot keys of old items
int count = 0;
foreach(MenuItem item in this.recentListeningMenu.MenuItems) {
RecentItem ri = (RecentItem)recentItems[recentItems.Count - count - 1];
if(count == 0) {
}
else if(count < 10)
item.Text = string.Format("&{3} {0} to {1}:{2}", ri.ListenPort,
ri.ResendHost, ri.ResendPort, count + 1);
else
item.Text = string.Format("{0} to {1}:{2}", ri.ListenPort,
ri.ResendHost, ri.ResendPort);
count++;
}
}
private void ClearAll()
{
clearing = true;
tcpListener.CancelAll();
treeNodes.Clear();
messageView.BeginUpdate();
messageView.Nodes.Clear();
messageView.EndUpdate();
messagesBox.Clear();
logMessages.Clear();
clearing = false;
}
private void Start(int listenPort, IPAddress resendHost, int resendPort)
{
if(tcpListener != null) tcpListener.StopListening();
tcpListener = new TcpListener(listenPort, resendHost, resendPort);
tcpListener.Log += new TcpLogEventHandler(TcpConnectionLog);
tcpListener.NewTcp += new TcpConnectionEventHandler(AddTcpConnection);
tcpListener.StartListening();
}
private void StartListening(int listenPort, IPAddress resendIp, int resendPort)
{
// listen to the port
try
{
Start(listenPort, resendIp, resendPort);
}
catch(Exception ex)
{
MessageBox.Show("Cannot start listening: " + ex.Message, "TCPproxy",
MessageBoxButtons.OK, MessageBoxIcon.Error);
Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
return;
}
AddRecentItem(listenPort, resendHost, resendPort);
startMenuItem.Enabled = false;
stopMenuItem.Enabled = true;
foreach(MenuItem subitem in recentListeningMenu.MenuItems) {
subitem.Enabled = false;
}
this.Text = string.Format("{0}: {1} to {2}:{3}",
defaultCaption, listenPort, resendHost, resendPort);
}
private void StopListening()
{
if(tcpListener != null) tcpListener.StopListening();
startMenuItem.Enabled = true;
stopMenuItem.Enabled = false;
if(recentItems.Count > 0) {
foreach(MenuItem subitem in recentListeningMenu.MenuItems) {
subitem.Enabled = true;
}
}
this.Text = defaultCaption;
}
private void CloseTcpConnection(TcpConnection tcp)
{
if(tcp == null) return;
tcp.Cancel();
}
private void SaveLog(string fileName)
{
StreamWriter writer = new StreamWriter(fileName);
foreach(LogMessage message in logMessages.Messages)
{
writer.WriteLine(message);
}
writer.Close();
}
private void SaveTcp(string fileName)
{
StreamWriter writer = new StreamWriter(fileName);
foreach(TreeNode tcpNode in messageView.Nodes)
{
TcpNodeData data = (TcpNodeData)tcpNode.Tag;
data.WriteLog(writer);
}
writer.Close();
}
private void SaveHttp(string fileName)
{
StreamWriter writer = new StreamWriter(fileName);
foreach(TreeNode tcpNode in messageView.Nodes)
{
foreach(TreeNode httpNode in tcpNode.Nodes)
{
HttpNodeData data = (HttpNodeData)httpNode.Tag;
data.WriteLog(writer);
}
}
writer.Close();
}
private void SaveXml(string fileName)
{
StreamWriter writer = new StreamWriter(fileName);
foreach(TreeNode tcpNode in messageView.Nodes)
{
foreach(TreeNode httpNode in tcpNode.Nodes)
{
foreach(TreeNode xmlNode in httpNode.Nodes)
{
XmlNodeData data = (XmlNodeData)xmlNode.Tag;
data.WriteLog(writer);
}
}
}
writer.Close();
}
private void SaveBinLog(string fileName)
{
FileStream file = new FileStream(fileName, FileMode.Create);
BinaryWriter writer = new BinaryWriter(file);
// header
writer.Write(Encoding.ASCII.GetBytes(LOG_BIN_HEADER));
writer.Write(LOG_TYPE_BIN);
// for each tcp connection
foreach(TreeNode tcpNode in messageView.Nodes)
((TcpNodeData)tcpNode.Tag).Tcp.WriteBinLog(writer);
// end of stream
writer.Write((byte)BinLogTypes.None);
writer.Close();
file.Close();
}
private void LoadBinLog(string fileName)
{
StopListening();
ClearAll();
FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader reader = new BinaryReader(file);
// header
byte[] bufExpect = Encoding.ASCII.GetBytes(LOG_BIN_HEADER);
if(file.Length < (bufExpect.Length + 1 /* the type */))
throw new Exception("The file is too short");
byte[] bufRead = reader.ReadBytes(bufExpect.Length);
for(int i = 0; i < bufRead.Length; i++)
if(bufRead[i] != bufExpect[i])
throw new Exception("Wrong header of the file");
if(reader.ReadByte() != LOG_TYPE_BIN)
throw new Exception("Unknown log type");
tcpListener = new TcpListener(0, null, 0);
tcpListener.Log += new TcpLogEventHandler(TcpConnectionLog);
tcpListener.NewTcp += new TcpConnectionEventHandler(AddTcpConnection);
tcpListener.ReadBinLog(reader); // it will send us usual event
reader.Close();
file.Close();
}
#endregion core methods
#region network events handlers
private void TcpConnectionLog(object sender, TcpLogEventArgs e)
{
if(clearing) return;
lock(this)
{
TcpConnection tcp = sender as TcpConnection;
LogMessage message = new LogMessage(tcp, e.Level, e.Message, e.Exception);
try
{
this.BeginInvoke(new AddLogMessageHandler(AddLogMessageInternal), new object[] { message } );
}
catch(InvalidOperationException ex)
{
if(!this.Disposing && !this.IsDisposed)
Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
}
}
}
private void AddTcpConnection(object sender, TcpConnectionEventArgs e)
{
lock(this)
{
e.Tcp.Log += new TcpLogEventHandler(TcpConnectionLog);
e.Tcp.Update += new TcpEventHandler(UpdateTcpNode);
e.Tcp.Close += new TcpEventHandler(UpdateTcpNode);
e.Tcp.NewHttp += new TcpHttpEventHandler(AddHttpMessageNode);
try
{
this.BeginInvoke(new AddTcpNodeHandler(AddTcpNodeInternal), new object[] { e.Tcp } );
}
catch(InvalidOperationException ex)
{
if(!this.Disposing && !this.IsDisposed)
Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
}
}
}
private void UpdateTcpNode(object sender, TcpEventArgs e)
{
lock(this)
{
try
{
this.BeginInvoke(new UpdateTcpNodeHandler(UpdateTcpNodeInternal), new object[] { (TcpConnection)sender } );
}
catch(InvalidOperationException ex)
{
if(!this.Disposing && !this.IsDisposed)
Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
}
}
}
private void AddHttpMessageNode(object sender, TcpHttpEventArgs e)
{
lock(this)
{
e.Http.Update += new TcpEventHandler(UpdateHttpNode);
try
{
this.BeginInvoke(new AddHttpNodeHandler(AddHttpNodeInternal),
new object[] { (TcpConnection)sender, e.Http } );
}
catch(InvalidOperationException ex)
{
if(!this.Disposing && !this.IsDisposed)
Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
}
}
}
private void UpdateHttpNode(object sender, TcpEventArgs e)
{
lock(this)
{
try
{
this.BeginInvoke(new UpdateHttpNodeHandler(UpdateHttpNodeInternal), new object[] { (HttpMessage)sender } );
}
catch(InvalidOperationException ex)
{
if(!this.Disposing && !this.IsDisposed)
Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
}
}
}
#endregion network events handlers
#region handlers for async GUI events
// All handlers are called in main application thread only, no locks needed.
// Other methods which are not running in the main application thread
// are not allowed no interact with GUI elemenents.
private delegate void AddLogMessageHandler(LogMessage message);
private delegate void AddTcpNodeHandler(TcpConnection tcp);
private delegate void UpdateTcpNodeHandler(TcpConnection tcp);
private delegate void AddHttpNodeHandler(TcpConnection tcp, HttpMessage http);
private delegate void UpdateHttpNodeHandler(HttpMessage http);
private void AddLogMessageInternal(LogMessage message)
{
logMessages.Add(message);
if(message.Exception != null)
{
Console.WriteLine(message.Exception.Message + " (" + message.Exception.GetType().Name
+ ")\n" + message.Exception.StackTrace);
}
}
private string TcpNodeTitle(TcpConnection tcp)
{
return tcp.Id + " " + tcp.StartTimestamp.ToString("HH:mm:ss.ffff");
}
private void AddTcpNodeInternal(TcpConnection tcp)
{
TreeNode treeNode = new TreeNode(TcpNodeTitle(tcp));
TcpNodeData data = new TcpNodeData(this, treeNode);
data.Tcp = tcp;
treeNode.Tag = data;
treeNode.ImageIndex = (tcp.LocalState == SocketState.Closed
&& tcp.RemoteState == SocketState.Closed) ? 2 : 1;
treeNode.SelectedImageIndex = treeNode.ImageIndex;
treeNodes[tcp] = data;
messageView.Nodes.Add(treeNode);
treeNode.EnsureVisible();
if(messageView.Nodes.Count == 1) {
//messageView.SelectedNode = messageView.Nodes[0];
}
}
private void UpdateTcpNodeInternal(TcpConnection tcp)
{
TcpNodeData data = treeNodes[tcp] as TcpNodeData;
if(data == null) return; // might be call by Cancel
string title = TcpNodeTitle(tcp);
if(title != data.Node.Text) data.Node.Text = title;
if(tcp.LocalState == SocketState.Closed && tcp.RemoteState == SocketState.Closed)
{
data.Node.ImageIndex = 2;
data.Node.SelectedImageIndex = data.Node.ImageIndex;
}
if(messageView.SelectedNode == null || data != messageView.SelectedNode.Tag)
data.ViewExpired = true; // got update for invisible TCP node, update it later
else
data.Show();
}
private string HttpNodeTitle(HttpMessage http)
{
return (http.Request.SoapAction != null ? ("SOAP " + http.Request.SoapAction)
: (http.Request.Method == null ? "" : http.Request.Method) + " " + (http.Request.Uri == null ? "" : http.Request.Uri));
}
private void AddHttpNodeInternal(TcpConnection tcp, HttpMessage http)
{
TreeNode treeNode = new TreeNode(HttpNodeTitle(http));
HttpNodeData data = new HttpNodeData(this, treeNode);
data.Http = http;
treeNode.Tag = data;
treeNodes[http] = data;
TcpNodeData tcpData = treeNodes[tcp] as TcpNodeData;
if(tcpData == null) throw new ArgumentException("No node found for TCP message");
tcpData.Node.Nodes.Add(treeNode);
if(autoExpand) tcpData.Node.Expand();
tcpData.Node.EnsureVisible();
}
private void UpdateHttpNodeInternal(HttpMessage http)
{
HttpNodeData httpData = treeNodes[http] as HttpNodeData;
if(httpData == null) return; // might be call by Cancel
string title = HttpNodeTitle(http);
if(httpData.Node.Text != title) httpData.Node.Text = title;
if(!httpData.RequestXmlShown && http.Request.Xml != null)
{
httpData.RequestXmlShown = true;
AddXmlNode(httpData.Node, "Request XML", http.Request.Xml);
if(autoExpand) httpData.Node.Expand();
}
if(!httpData.ResponseXmlShown && http.Response.Xml != null)
{
httpData.ResponseXmlShown = true;
AddXmlNode(httpData.Node, "Response XML", http.Response.Xml);
if(autoExpand) httpData.Node.Expand();
}
// update text view
if(messageView.SelectedNode == null || httpData != messageView.SelectedNode.Tag)
httpData.ViewExpired = true;
else
httpData.Show();
}
private void AddXmlNode(TreeNode parent, string title, XmlMessage xml)
{
TreeNode treeNode = new TreeNode(title);
XmlNodeData data = new XmlNodeData(this, treeNode);
data.Xml = xml;
treeNode.Tag = data;
treeNodes[xml] = data;
parent.Nodes.Add(treeNode);
}
#endregion handlers for async GUI events
#region node display classes
private abstract class TreeNodeData
{
protected TreeNode node;
protected object viewState;
protected bool viewExpired;
protected MainForm owner;
protected bool shown = false;
public TreeNode Node
{
get { return node; }
}
public TreeNodeData(MainForm owner, TreeNode node)
{
this.owner = owner;
this.node = node;
}
public bool ViewExpired
{
get { return viewExpired; }
set { viewExpired = value; }
}
public void SaveViewState()
{
viewState = owner.messagesBox.SaveState(false);
}
protected virtual bool ForceInitView()
{
return false;
}
protected abstract void InitView();
protected abstract void UpdateView();
public void Show()
{
if(!shown || viewState == null || ForceInitView())
{
InitView();
shown = true;
if(viewState == null) viewState = owner.messagesBox.SaveState(false);
}
else
{
owner.messagesBox.RestoreState(viewState, true);
if(viewExpired) UpdateView();
}
}
public abstract void WriteLog(StreamWriter writer);
}
private class TcpNodeData : TreeNodeData
{
private TcpConnection tcp;
private TcpShowMode lastShowMode;
private object localStateMarker = null;
private object remoteStateMarker = null;
private object startMarker = null;
private object localEndMarker = null;
private object remoteEndMarker = null;
private object clientMarker = null;
private object serverMarker = null;
private object sentMarker = null;
private object receivedMarker = null;
private object textMarker1 = null;
private object textMarker2 = null;
private IEnumerator messagesEnum = null;
public TcpConnection Tcp
{
get { return tcp; }
set { tcp = value; }
}
public TcpNodeData(MainForm owner, TreeNode node) : base(owner, node)
{
}
protected override bool ForceInitView()
{
return (lastShowMode != owner.tcpShowMode);
}
protected override void InitView()
{
lastShowMode = owner.tcpShowMode;
try
{
owner.messagesBox.BeginUpdate();
lock(tcp)
{
owner.messagesBox.Clear();
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("ID: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
owner.messagesBox.AppendText(tcp.Id,
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("State: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
localStateMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(tcp.LocalState.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(localStateMarker);
owner.messagesBox.AppendText(null,
Color.DarkRed, Color.Transparent, false, false, 1, 12);
remoteStateMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(tcp.RemoteState.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(remoteStateMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Start: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
startMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(tcp.StartTimestamp.ToString("HH:mm:ss.ffff"),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(startMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Local End: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
localEndMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(tcp.LocalEndTimestamp.ToString("HH:mm:ss.ffff"),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(localEndMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Remote End: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
remoteEndMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(tcp.RemoteEndTimestamp.ToString("HH:mm:ss.ffff"),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(remoteEndMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Client: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
clientMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText((tcp.LocalPoint == null) ? "" : tcp.LocalPoint.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(clientMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Server: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
serverMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText((tcp.RemotePoint == null) ? "" : tcp.RemotePoint.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(serverMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Sent: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
sentMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(tcp.SentBytes.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(sentMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Received: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
receivedMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(tcp.ReceivedBytes.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.EndMark(receivedMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendNewLine();
messagesEnum = tcp.Messages.GetEnumerator();
textMarker1 = owner.messagesBox.BeginMark();
owner.messagesBox.EndMark(textMarker1);
owner.messagesBox.AppendNewLine();
textMarker2 = owner.messagesBox.BeginMark();
owner.messagesBox.EndMark(textMarker2);
ShowMessages();
}
}
finally
{
owner.messagesBox.EndUpdate();
}
}
protected override void UpdateView()
{
try
{
owner.messagesBox.BeginUpdate();
lock(tcp)
{
owner.messagesBox.ChangeText(localStateMarker, tcp.LocalState.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.ChangeText(remoteStateMarker, tcp.RemoteState.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.ChangeText(startMarker, tcp.StartTimestamp.ToString("HH:mm:ss.ffff"),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.ChangeText(localEndMarker, tcp.LocalEndTimestamp.ToString("HH:mm:ss.ffff"),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.ChangeText(remoteEndMarker, tcp.RemoteEndTimestamp.ToString("HH:mm:ss.ffff"),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.ChangeText(clientMarker, (tcp.LocalPoint == null) ? "" : tcp.LocalPoint.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.ChangeText(serverMarker, (tcp.RemotePoint == null) ? "" : tcp.RemotePoint.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.ChangeText(sentMarker, tcp.SentBytes.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
owner.messagesBox.ChangeText(receivedMarker, tcp.ReceivedBytes.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 12);
ShowMessages();
}
}
finally
{
owner.messagesBox.EndUpdate();
}
}
private void ShowMessages()
{
while(messagesEnum.MoveNext())
{
TcpMessage message = (TcpMessage)messagesEnum.Current;
object marker = (owner.tcpShowMode == TcpShowMode.ByTime
|| message.Direction == TcpMessageDirection.Local) ? textMarker1 : textMarker2;
if(owner.tcpShowMode == TcpShowMode.ByTime)
{
owner.messagesBox.InsertText(marker,
message.Timestamp.ToString("HH:mm:ss.ffff") + " (" + message.Length + ")",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
owner.messagesBox.InsertNewLine(marker);
}
string str = Utils.BytesToString(message.Bytes, message.Length);
ArrayList lines = Utils.SplitLine(str);
for(int i = 0; i < lines.Count; i++)
{
owner.messagesBox.InsertText(marker, (string)lines[i],
message.Direction == TcpMessageDirection.Local ? Color.Green : Color.Blue,
Color.LightGray, false, false, 0, 0);
if(owner.tcpShowMode == TcpShowMode.ByTime || i != lines.Count - 1)
owner.messagesBox.InsertNewLine(marker);
}
}
}
public override void WriteLog(StreamWriter writer)
{
writer.WriteLine(
"Start: " + tcp.StartTimestamp.ToString("HH:mm:ss.ffff")
+ "\r\nLocal End: " + tcp.LocalEndTimestamp.ToString("HH:mm:ss.ffff")
+ "\r\nRemote End: " + tcp.RemoteEndTimestamp.ToString("HH:mm:ss.ffff")
+ "\r\nClient: " + ((tcp.LocalPoint == null) ? "" : tcp.LocalPoint.ToString())
+ "\r\nServer: " + ((tcp.RemotePoint == null) ? "" : tcp.RemotePoint.ToString())
+ "\r\nSent: " + tcp.SentBytes
+ "\r\nReceived: " + tcp.ReceivedBytes);
foreach(TcpMessage message in tcp.Messages)
{
string str = Utils.BytesToString(message.Bytes, message.Length);
if(!str.EndsWith("\n")) str += "\r\n";
writer.WriteLine();
if(message.Direction == TcpMessageDirection.Local)
writer.WriteLine(">>> {0:HH:mm:ss.ffff} >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", message.Timestamp);
else
writer.WriteLine("<<< {0:HH:mm:ss.ffff} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<", message.Timestamp);
writer.Write(str);
}
writer.WriteLine("===============================================================");
writer.WriteLine();
}
}
private class HttpNodeData : TreeNodeData
{
private class MarkerSet
{
public object start;
public object method;
public object uri;
public object version;
public object status;
public object transferEncoding;
public object length;
public object contentEncoding;
public object contentType;
public object charset;
public object headers;
public object body;
public IEnumerator headersEnum;
}
private HttpMessage http;
private bool requestXmlShown = false;
private bool responseXmlShown = false;
private object stateMarker = null;
private MarkerSet requestMarkers = new MarkerSet();
private MarkerSet responseMarkers = new MarkerSet();
public HttpMessage Http
{
get { return http; }
set { http = value; }
}
public bool RequestXmlShown
{
get { return requestXmlShown; }
set { requestXmlShown = value; }
}
public bool ResponseXmlShown
{
get { return responseXmlShown; }
set { responseXmlShown = value; }
}
public HttpNodeData(MainForm owner, TreeNode node) : base(owner, node)
{
}
private string EncodingToString(HttpTransferEncoding encoding)
{
switch(encoding)
{
case HttpTransferEncoding.None: return "none";
case HttpTransferEncoding.Identity: return "identity";
case HttpTransferEncoding.Chunked: return "chunked";
case HttpTransferEncoding.Gzip: return "gzip";
case HttpTransferEncoding.Compress: return "compress";
case HttpTransferEncoding.Deflate: return "deflate";
default: return "<unknown>";
}
}
private string EncodingToString(HttpContentEncoding encoding)
{
switch(encoding)
{
case HttpContentEncoding.None: return "none";
case HttpContentEncoding.Identity: return "identity";
case HttpContentEncoding.Gzip: return "gzip";
case HttpContentEncoding.Compress: return "compress";
case HttpContentEncoding.Deflate: return "deflate";
default: return "<unknown>";
}
}
private string VersionToString(HttpVersion version)
{
switch(version)
{
case HttpVersion.V0_9: return "HTTP/0.9";
case HttpVersion.V1_0: return "HTTP/1.0";
default: return "HTTP/1.1";
}
}
private void InitHttpHalfView(HttpHalfMessage half, MarkerSet markers, string title)
{
string padding = "";
owner.messagesBox.AppendText(title + " Start: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.start = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(half.StartTimestamp == DateTime.MinValue
? "<unknown>" : half.StartTimestamp.ToString("HH:mm:ss.ffff"),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.start);
owner.messagesBox.AppendNewLine();
if(half.IsRequest)
{
owner.messagesBox.AppendText(title + " Method: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.method = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText((half as HttpRequest).Method,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.method);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(title + " URI: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.uri = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText((half as HttpRequest).Uri,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.uri);
owner.messagesBox.AppendNewLine();
}
else
{
owner.messagesBox.AppendText(title + " Status: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.status = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText((half as HttpResponse).StatusCode
+ " " + (half as HttpResponse).StatusMessage,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.status);
owner.messagesBox.AppendNewLine();
}
owner.messagesBox.AppendText(title + " Version: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.version = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(VersionToString(half.Version),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.version);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(title + " Transfer Encoding: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.transferEncoding = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(EncodingToString(half.TransferEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.transferEncoding);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(title + " Content Length: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.length = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(half.Length < 0 ? "<unknown>" : half.Length.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.length);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(title + " Content Encoding: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.contentEncoding = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(EncodingToString(half.ContentEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.contentEncoding);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(title + " Content Type: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.contentType = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(half.ContentType == null ? "<unknown>"
: half.ContentType + "/" + half.ContentSubtype,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.contentType);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(title + " Content Charset: " + padding,
Color.DarkRed, Color.Transparent, false, false, 0, 0);
markers.charset = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(half.Charset == null ? "<unknown>" : half.Charset,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(markers.charset);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(title + " Headers:",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
owner.messagesBox.AppendNewLine();
markers.headers = owner.messagesBox.BeginMark();
owner.messagesBox.EndMark(markers.headers);
markers.headersEnum = half.Headers.GetEnumerator();
ShowHeaders(markers.headersEnum, markers.headers);
}
private void UpdateHttpHalfView(HttpHalfMessage half, MarkerSet markers)
{
if(half.IsRequest)
{
owner.messagesBox.ChangeText(markers.method, (half as HttpRequest).Method,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(markers.uri, (half as HttpRequest).Uri,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
}
else
{
owner.messagesBox.ChangeText(markers.status, (half as HttpResponse).StatusCode + " " + (half as HttpResponse).StatusMessage,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
}
owner.messagesBox.ChangeText(markers.version, VersionToString(half.Version),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(markers.transferEncoding, EncodingToString(half.TransferEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(markers.length, half.Length < 0
? "<unknown>" : half.Length.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(markers.contentEncoding, EncodingToString(half.ContentEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(markers.contentType, half.ContentType == null ? "<unknown>"
: half.ContentType + "/" + half.ContentSubtype,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(markers.charset, half.Charset == null
? "<unknown>" : half.Charset,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
ShowHeaders(markers.headersEnum, markers.headers);
}
protected override void InitView()
{
try
{
lock(http)
{
owner.messagesBox.BeginUpdate();
owner.messagesBox.Clear();
// state
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Complete: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
stateMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.Request.Complete && http.Response.Complete ? "YES" : "NO",
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(stateMarker);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendNewLine();
// general info
InitHttpHalfView(http.Request, requestMarkers, "Request");
InitHttpHalfView(http.Response, responseMarkers, "Response");
// bodies
owner.messagesBox.AppendNewLine();
requestMarkers.body = owner.messagesBox.BeginMark();
owner.messagesBox.EndMark(requestMarkers.body);
ShowBody(requestMarkers, http.Request, Color.Green);
owner.messagesBox.AppendNewLine();
responseMarkers.body = owner.messagesBox.BeginMark();
owner.messagesBox.EndMark(responseMarkers.body);
ShowBody(responseMarkers, http.Response, Color.Blue);
}
}
finally
{
owner.messagesBox.EndUpdate();
}
}
protected override void UpdateView()
{
try
{
owner.messagesBox.BeginUpdate();
lock(http)
{
// state
owner.messagesBox.ChangeText(stateMarker, http.Request.Complete && http.Response.Complete ? "YES" : "NO",
Color.DarkRed, Color.LightGray, false, false, 0, 27);
// general info
UpdateHttpHalfView(http.Request, requestMarkers);
UpdateHttpHalfView(http.Response, responseMarkers);
// bodies
owner.messagesBox.DeleteText(requestMarkers.body);
ShowBody(requestMarkers, http.Request, Color.Green);
owner.messagesBox.DeleteText(responseMarkers.body);
ShowBody(responseMarkers, http.Response, Color.Blue);
}
}
finally
{
owner.messagesBox.EndUpdate();
}
}
private void ShowHeaders(IEnumerator headers, object marker)
{
while(headers.MoveNext())
{
HttpHeader h = (HttpHeader)headers.Current;
bool first = true;
foreach(string val in h.Values)
{
if(first)
{
owner.messagesBox.InsertText(marker, h.Name + ":",
Color.DarkRed, Color.Transparent, false, false, 4, 4);
owner.messagesBox.InsertText(marker, null,
Color.DarkRed, Color.Transparent, false, false, 6 - 4 - 1, 4);
first = false;
}
else
{
owner.messagesBox.InsertText(marker, null,
Color.DarkRed, Color.Transparent, false, false, 6 + h.Name.Length, 6 + h.Name.Length);
}
owner.messagesBox.InsertText(marker, val,
Color.DarkRed, Color.LightGray, false, false, 0, 6 + h.Name.Length);
owner.messagesBox.InsertNewLine(marker);
}
}
}
private void ShowBody(MarkerSet markers, HttpHalfMessage half, Color color)
{
if(half.Text != null)
{
ArrayList lines = Utils.SplitLine(half.Text);
for(int i = 0; i < lines.Count; i++)
{
owner.messagesBox.InsertText(markers.body, (string)lines[i], color, Color.LightGray, false, false, 0, 0);
owner.messagesBox.InsertNewLine(markers.body);
}
}
else if(half.Body != null)
{
ArrayList lines = Utils.SplitLine(Utils.BytesToString(half.Body, half.Length));
for(int i = 0; i < lines.Count; i++)
{
owner.messagesBox.InsertText(markers.body, (string)lines[i], color, Color.LightGray, false, false, 0, 0);
owner.messagesBox.InsertNewLine(markers.body);
}
}
}
public override void WriteLog(StreamWriter writer)
{
// request info
writer.WriteLine(
"Complete: " + (http.Request.Complete && http.Response.Complete ? "YES" : "NO") + "\r\n"
+ "\r\nRequest Method: " + http.Request.Method
+ "\r\nRequest URI: " + http.Request.Uri
+ "\r\nRequest Version: " + (http.Request.Version == HttpVersion.V0_9 ? "HTTP/0.9"
: http.Request.Version == HttpVersion.V1_0 ? "HTTP/1.0" : "HTTP/1.1")
+ "\r\nRequest Transfer Encoding: " + EncodingToString(http.Request.TransferEncoding)
+ "\r\nRequest Content Length: " + (http.Request.Length < 0 ? "<unknown>" : http.Request.Length.ToString())
+ "\r\nRequest Content Encoding: " + EncodingToString(http.Request.ContentEncoding)
+ "\r\nRequest Content Type: " + (http.Request.ContentType == null ? "<unknown>"
: http.Request.ContentType + "/" + http.Request.ContentSubtype)
+ "\r\nRequest Content Charset: " + (http.Request.Charset == null ? "<unknown>" : http.Request.Charset)
+ "\r\nRequest Headers:");
foreach(HttpHeader h in http.Request.Headers)
{
int indent = 0;
foreach(string val in h.Values)
{
if(indent == 0)
{
writer.WriteLine(" {0}: {1}", h.Name, val);
indent = 6 + h.Name.Length;
}
else
{
writer.WriteLine("{0," + indent + "}{1}", " ", val);
}
}
}
// response info
writer.WriteLine(
"\r\nResponse Version: " + (http.Response.Version == HttpVersion.V0_9
? "HTTP/0.9" : http.Response.Version == HttpVersion.V1_0 ? "HTTP/1.0" : "HTTP/1.1")
+ "\r\nResponse Status: " + http.Response.StatusCode + " " + http.Response.StatusMessage
+ "\r\nResponse Transfer Encoding: " + EncodingToString(http.Response.TransferEncoding)
+ "\r\nResponse Content Length: " + (http.Response.Length < 0
? "<unknown>" : http.Response.Length.ToString())
+ "\r\nResponse Content Encoding: " + EncodingToString(http.Response.ContentEncoding)
+ "\r\nResponse Content Type: " + (http.Response.ContentType == null ? "<unknown>"
: http.Response.ContentType + "/" + http.Response.ContentSubtype)
+ "\r\nResponse Content Charset: " + (http.Response.Charset == null ? "<unknown>" : http.Response.Charset)
+ "\r\nResponse Headers:");
foreach(HttpHeader h in http.Response.Headers)
{
int indent = 0;
foreach(string val in h.Values)
{
if(indent == 0)
{
writer.WriteLine(" {0}: {1}", h.Name, val);
indent = 6 + h.Name.Length;
}
else
{
writer.WriteLine("{0," + indent + "}{1}", " ", val);
}
}
}
writer.WriteLine();
// request body
if(http.Request.Text != null)
{
writer.WriteLine(http.Request.Text);
}
else if(http.Request.Body != null)
{
writer.WriteLine(Utils.BytesToString(http.Request.Body, http.Request.Length));
}
// response body
if(http.Response.Text != null)
{
writer.WriteLine(http.Response.Text);
}
else if(http.Response.Body != null)
{
writer.WriteLine(Utils.BytesToString(http.Response.Body, http.Response.Length));
}
writer.WriteLine("===============================================================");
writer.WriteLine();
}
}
private class XmlNodeData : TreeNodeData
{
private XmlMessage xml;
public XmlMessage Xml
{
get { return xml; }
set { xml = value; }
}
public XmlNodeData(MainForm owner, TreeNode node) : base(owner, node)
{
}
protected override void InitView()
{
try
{
// update main screen if necessary
owner.messagesBox.BeginUpdate();
lock(xml)
{
owner.messagesBox.Clear();
if(xml.ParseException != null)
{
owner.messagesBox.AppendText("Cannot parse XML:",
Color.Red, Color.Transparent, false, false, 0, 0);
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(xml.ParseException.Message,
Color.Red, Color.Transparent, false, false, 2, 2);
owner.messagesBox.AppendNewLine();
}
else if(xml.Xml != null)
{
ShowXmlNode(xml.Xml, 0);
}
}
}
finally
{
owner.messagesBox.EndUpdate();
}
}
protected override void UpdateView()
{
}
private void ShowXmlNode(XmlNode node, int indent)
{
if(node.NodeType == XmlNodeType.Document)
{
foreach(XmlNode subnode in node.ChildNodes)
{
ShowXmlNode(subnode, indent);
}
}
else if(node.NodeType == XmlNodeType.XmlDeclaration)
{
owner.messagesBox.AppendText("<?" + node.Name + " " + node.Value + " ?>",
Color.Blue, Color.Transparent, false, false, indent, indent+2);
owner.messagesBox.AppendNewLine();
}
else if(node.NodeType == XmlNodeType.Comment)
{
owner.messagesBox.AppendText("<!--", Color.Gray, Color.Transparent, false, false, indent, indent + 2);
ShowNormalizedXmlValue(node.Value, Color.Gray, Color.Thistle, false, false, indent);
owner.messagesBox.AppendText("-->", Color.Gray, Color.Transparent, false, false, 0, indent + 2);
owner.messagesBox.AppendNewLine();
}
else if(node.NodeType == XmlNodeType.Element)
{
owner.messagesBox.AppendText("<", Color.Blue, Color.Transparent, false, false, indent, indent + 2);
owner.messagesBox.AppendText(node.Name, Color.DarkRed, Color.Transparent, false, false, 0, indent + 2);
foreach(XmlAttribute attr in node.Attributes)
{
bool xmlAttr = attr.Name.StartsWith("xml");
owner.messagesBox.AppendText(attr.Name, xmlAttr ? Color.Red : Color.DarkRed, Color.Transparent, false, false, 1, indent + 2);
owner.messagesBox.AppendText("=\"", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
owner.messagesBox.AppendText(attr.Value, xmlAttr ? Color.Red : Color.DarkRed, Color.Transparent, false, false, 0, indent + 2);
owner.messagesBox.AppendText("\"", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
}
if(!node.HasChildNodes)
{
owner.messagesBox.AppendText(" />", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
owner.messagesBox.AppendNewLine();
}
else
{
owner.messagesBox.AppendText(">", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
bool elementExists = false;
bool lastText = true;
foreach(XmlNode subnode in node.ChildNodes)
{
if(subnode.NodeType == XmlNodeType.Text)
{
if(elementExists) owner.messagesBox.AppendNewLine();
ShowNormalizedXmlValue(subnode.Value, Color.Black, Color.LightGray, false, false, indent);
lastText = true;
}
else
{
if(lastText) owner.messagesBox.AppendNewLine();
ShowXmlNode(subnode, indent + 2);
elementExists = true;
lastText = false;
}
}
if(elementExists) owner.messagesBox.AppendText(null, Color.Black, Color.Transparent, false, false, indent, indent + 2);
owner.messagesBox.AppendText("</", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
owner.messagesBox.AppendText(node.Name, Color.DarkRed, Color.Transparent, false, false, 0, indent + 2);
owner.messagesBox.AppendText(">", Color.Blue, Color.Transparent, false, false, 0, indent + 2);
owner.messagesBox.AppendNewLine();
}
}
}
private void ShowNormalizedXmlValue(string s, Color color, Color backColor, bool italic, bool bold, int indent)
{
int begin;
int end;
bool newLineFound = false;
foreach(char c in s)
{
if(c == '\n')
{
newLineFound = true;
break;
}
}
if(newLineFound)
{
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(null, color, Color.Transparent, italic, bold, indent, indent);
owner.messagesBox.AppendText(null, color, backColor, italic, bold, 2, 2);
}
// trim
for(begin = 0; begin < s.Length; begin++)
{
char c = s[begin];
if(c != '\n' && c != '\r' && c != '\t' && c != ' ') break;
}
for(end = s.Length-1; end >= 0; end--)
{
char c = s[end];
if(c != '\n' && c != '\r' && c != '\t' && c != ' ') break;
}
StringBuilder b = new StringBuilder(s.Length);
for(int i = begin; i <= end; i++)
{
char c = s[i];
switch(c)
{
case '\n':
if(b.Length > 0)
{
owner.messagesBox.AppendText(b.ToString(), color, backColor, italic, bold, 0, indent + 2);
b.Length = 0;
}
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(null, color, Color.Transparent, italic, bold, indent, indent);
owner.messagesBox.AppendText(null, color, backColor, italic, bold, 2, 2);
break;
case '\r':
break;
case '\t':
b.Append(" ");
break;
default:
b.Append(c);
break;
}
}
if(b.Length > 0)
owner.messagesBox.AppendText(b.ToString(), color, backColor, italic, bold, 0, indent + 2);
if(newLineFound)
{
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText(null, color, Color.Transparent, italic, bold, indent, indent + 2);
}
}
public override void WriteLog(StreamWriter writer)
{
WriteXmlNode(writer, xml.Xml, "");
writer.WriteLine("===============================================================");
writer.WriteLine();
}
private void WriteXmlNode(StreamWriter writer, XmlNode node, string indent)
{
if(node.NodeType == XmlNodeType.Document)
{
foreach(XmlNode subnode in node.ChildNodes)
{
WriteXmlNode(writer, subnode, indent);
}
}
else if(node.NodeType == XmlNodeType.XmlDeclaration)
{
writer.WriteLine(indent + "<?" + node.Name + " " + node.Value + " ?>");
}
else if(node.NodeType == XmlNodeType.Comment)
{
writer.Write(indent + "<!--");
WriteNormalizedXmlValue(writer, node.Value, indent);
writer.WriteLine("-->");
}
else if(node.NodeType == XmlNodeType.Element)
{
writer.Write(indent + "<" + node.Name);
foreach(XmlAttribute attr in node.Attributes)
{
bool xmlAttr = attr.Name.StartsWith("xml");
writer.Write(" " + attr.Name + "=\"" + attr.Value + "\"");
}
if(!node.HasChildNodes)
{
writer.WriteLine(" />");
}
else
{
writer.Write(">");
bool elementExists = false;
bool lastText = true;
foreach(XmlNode subnode in node.ChildNodes)
{
if(subnode.NodeType == XmlNodeType.Text)
{
if(elementExists) writer.WriteLine();
WriteNormalizedXmlValue(writer, subnode.Value, indent);
lastText = true;
}
else
{
if(lastText) writer.WriteLine();
WriteXmlNode(writer, subnode, indent + " ");
elementExists = true;
lastText = false;
}
}
if(elementExists) writer.Write(indent);
writer.WriteLine("</" + node.Name + ">");
}
}
}
private void WriteNormalizedXmlValue(StreamWriter writer, string s, string indent)
{
int begin;
int end;
bool newLineFound = false;
foreach(char c in s)
{
if(c == '\n')
{
newLineFound = true;
break;
}
}
if(newLineFound)
{
writer.WriteLine();
writer.Write(indent + " ");
}
// trim
for(begin = 0; begin < s.Length; begin++)
{
char c = s[begin];
if(c != '\n' && c != '\r' && c != '\t' && c != ' ') break;
}
for(end = s.Length-1; end >= 0; end--)
{
char c = s[end];
if(c != '\n' && c != '\r' && c != '\t' && c != ' ') break;
}
StringBuilder b = new StringBuilder(s.Length);
for(int i = begin; i <= end; i++)
{
char c = s[i];
switch(c)
{
case '\n':
if(b.Length > 0)
{
writer.Write(b.ToString());
b.Length = 0;
}
writer.WriteLine();
writer.Write(indent + " ");
break;
case '\r':
break;
case '\t':
b.Append(" ");
break;
case '&':
b.Append("&");
break;
case '<':
b.Append("<");
break;
case '>':
b.Append(">");
break;
default:
b.Append(c);
break;
}
}
if(b.Length > 0)
writer.Write(b.ToString());
if(newLineFound)
{
writer.WriteLine();
writer.Write(indent + " ");
}
}
}
#endregion node display classes
#region other classes
private abstract class Utils
{
public static string BytesToString(byte[] bytes, int length)
{
if(bytes == null) return null;
char[] chars = new char[length + 1];
Decoder decoder = System.Text.Encoding.UTF8.GetDecoder();
int charLen = decoder.GetChars(bytes, 0, length, chars, 0);
for(int i = 0; i < charLen; i++)
{
char c = chars[i];
if(c != '\n' && c != '\r' && Char.IsControl(c)) chars[i] = '.';
}
return (new System.String(chars)).Substring(0, charLen);
}
public static ArrayList SplitLine(string line)
{
if(line == null) return null;
ArrayList res = new ArrayList();
StringBuilder b = new StringBuilder(200);
foreach(char c in line)
{
switch(c)
{
case '\r':
break;
case '\n':
res.Add(b.ToString());
b.Length = 0;
break;
default:
b.Append(c);
break;
}
}
res.Add(b.ToString());
return res;
}
}
#endregion other classes
}
public class LogMessages
{
private ArrayList messages = new ArrayList();
private ListBox logBox;
private LogLevel level = LogLevel.Debug;
public LogLevel Level
{
get { return level; }
set { level = value; Update(); }
}
public LogMessages(ListBox logBox)
{
this.logBox = logBox;
}
public ArrayList Messages
{
get { return new ArrayList(messages); }
}
public void Add(LogMessage message)
{
messages.Add(message);
if(Show(message))
logBox.TopIndex = logBox.Items.Count - 1;
}
public void Clear()
{
messages.Clear();
logBox.Items.Clear();
}
public void Update()
{
logBox.BeginUpdate();
logBox.Items.Clear();
foreach(LogMessage message in messages)
{
Show(message);
}
logBox.TopIndex = logBox.Items.Count - 1;
logBox.EndUpdate();
}
private bool Show(LogMessage message)
{
if(message.Level > this.level) return false;
try
{
logBox.Items.Add(message.ToString());
}
catch(ObjectDisposedException) {}
return true;
}
}
public class LogMessage
{
private TcpConnection tcp;
private LogLevel level;
private string message;
private Exception exception;
private DateTime timestamp = DateTime.Now;
public TcpConnection Tcp
{
get { return tcp; }
set { tcp = value; }
}
public LogLevel Level
{
get { return level; }
set { level = value; }
}
public string Message
{
get { return message; }
set { message = value; }
}
public Exception Exception
{
get { return exception; }
set { exception = value; }
}
public DateTime Timestamp
{
get { return timestamp; }
set { timestamp = value; }
}
public LogMessage(TcpConnection tcp, LogLevel level, string message, Exception exception)
{
this.tcp = tcp;
this.level = level;
this.message = message;
this.exception = exception;
}
public override string ToString()
{
string l = " ";
switch(level)
{
case LogLevel.Debug: l = "debug"; break;
case LogLevel.Info: l = "info "; break;
case LogLevel.Important: l = "Imp "; break;
case LogLevel.Warning: l = "Warn "; break;
case LogLevel.Error: l = "ERROR"; break;
case LogLevel.Critical: l = "CRIT "; break;
}
return (tcp == null ? "...." : tcp.Id) + " " + l + " " + timestamp.ToString("HH:mm:ss.ffff") + " "
+ (exception != null ? exception.Message : message);
}
}
public enum TcpShowMode
{
ByDirection,
ByTime
}
public class RecentItem : IComparable
{
private int listenPort;
public int ListenPort
{
get { return listenPort; }
set { listenPort = value; }
}
private string resendHost;
public string ResendHost
{
get { return resendHost; }
set { resendHost = value; }
}
private int resendPort;
public int ResendPort
{
get { return resendPort; }
set { resendPort = value; }
}
private DateTime timestamp;
public DateTime Timestamp
{
get { return timestamp; }
}
public RecentItem(int listenPort, string resendHost, int resendPort)
{
this.listenPort = listenPort;
this.resendHost = resendHost;
this.resendPort = resendPort;
}
public override string ToString()
{
return string.Format("{0} to {1}:{2} at {3:HH:mm:ss.ff}",
listenPort, resendHost, resendPort, timestamp);
}
public override bool Equals(object obj)
{
if(!(obj is RecentItem)) return false;
RecentItem i2 = (RecentItem)obj;
return (i2.listenPort == this.listenPort) && (i2.resendHost == this.resendHost)
&& (i2.resendPort == this.resendPort);
}
public override int GetHashCode()
{
return this.resendHost.GetHashCode();
}
public string SaveToRegistry()
{
return string.Format("{0}:{1}:{2}:{3}",
listenPort, resendPort, timestamp.Ticks, resendHost);
}
public static RecentItem LoadFromRegistry(string str)
{
Regex re = new Regex(@"^(\d+):(\d+):(\d+):(.+)$");
Match m = re.Match(str);
if(!m.Success) throw new Exception("Cannot parse recent item");
RecentItem item = new RecentItem(int.Parse(m.Groups[1].Value),
m.Groups[4].Value, int.Parse(m.Groups[2].Value));
item.timestamp = new DateTime(long.Parse(m.Groups[3].Value));
return item;
}
public void UpdateTimestamp()
{
timestamp = DateTime.Now;
}
public void UpdateTimestamp(RecentItem second)
{
if(second.timestamp > timestamp)
timestamp = second.timestamp;
}
#region IComparable Members
int IComparable.CompareTo(object obj)
{
if(!(obj is RecentItem))
throw new Exception("Cannot compare");
return this.timestamp.CompareTo(((RecentItem)obj).timestamp);
}
#endregion
}
}