Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1232 → Rev 1233

/TCPproxy/trunk/HostUtils.cs
30,7 → 30,7
}
else
{
IPHostEntry hostInfo = Dns.GetHostByName(host);
IPHostEntry hostInfo = Dns.GetHostEntry(host);
 
if(hostInfo.AddressList.Length > 0)
{
/TCPproxy/trunk/ListenForm.cs
35,74 → 35,74
/// </summary>
private void InitializeComponent()
{
this.startButton = new Button();
this.label2 = new Label();
this.label1 = new Label();
this.resendPortBox = new TextBox();
this.resendHostBox = new TextBox();
this.listenPortBox = new TextBox();
this.cancelButton = new Button();
this.startButton = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.resendPortBox = new System.Windows.Forms.TextBox();
this.resendHostBox = new System.Windows.Forms.TextBox();
this.listenPortBox = new System.Windows.Forms.TextBox();
this.cancelButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
//
// startButton
//
//
this.startButton.Location = new System.Drawing.Point(136, 62);
this.startButton.Name = "startButton";
this.startButton.Size = new System.Drawing.Size(75, 23);
this.startButton.TabIndex = 12;
this.startButton.TabIndex = 60;
this.startButton.Text = "Listen";
this.startButton.Click += new System.EventHandler(this.startButton_Click);
//
//
// label2
//
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(12, 35);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(56, 13);
this.label2.TabIndex = 10;
this.label2.Text = "Resend to";
//
this.label2.TabIndex = 30;
this.label2.Text = "&Resend to";
//
// label1
//
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(71, 13);
this.label1.TabIndex = 7;
this.label1.Text = "Listen on port";
//
this.label1.TabIndex = 10;
this.label1.Text = "Listen &on port";
//
// resendPortBox
//
//
this.resendPortBox.Location = new System.Drawing.Point(220, 32);
this.resendPortBox.Name = "resendPortBox";
this.resendPortBox.Size = new System.Drawing.Size(72, 20);
this.resendPortBox.TabIndex = 9;
//
this.resendPortBox.TabIndex = 50;
//
// resendHostBox
//
//
this.resendHostBox.Location = new System.Drawing.Point(114, 32);
this.resendHostBox.Name = "resendHostBox";
this.resendHostBox.Size = new System.Drawing.Size(100, 20);
this.resendHostBox.TabIndex = 8;
//
this.resendHostBox.TabIndex = 40;
//
// listenPortBox
//
//
this.listenPortBox.Location = new System.Drawing.Point(114, 6);
this.listenPortBox.Name = "listenPortBox";
this.listenPortBox.Size = new System.Drawing.Size(100, 20);
this.listenPortBox.TabIndex = 6;
//
this.listenPortBox.TabIndex = 20;
//
// cancelButton
//
this.cancelButton.DialogResult = DialogResult.Cancel;
//
this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.cancelButton.Location = new System.Drawing.Point(217, 62);
this.cancelButton.Name = "cancelButton";
this.cancelButton.Size = new System.Drawing.Size(75, 23);
this.cancelButton.TabIndex = 13;
this.cancelButton.TabIndex = 70;
this.cancelButton.Text = "Cancel";
//
//
// ListenForm
//
//
this.AcceptButton = this.startButton;
this.CancelButton = this.cancelButton;
this.ClientSize = new System.Drawing.Size(301, 91);
113,15 → 113,16
this.Controls.Add(this.resendPortBox);
this.Controls.Add(this.resendHostBox);
this.Controls.Add(this.listenPortBox);
this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ListenForm";
this.ShowInTaskbar = false;
this.StartPosition = FormStartPosition.CenterParent;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "TCPproxy - Start Listening";
this.ResumeLayout(false);
this.PerformLayout();
 
}
 
#endregion
/TCPproxy/trunk/MainForm.cs
1762,28 → 1762,30
private bool requestXmlShown = false;
private bool responseXmlShown = false;
 
private object stateMarker = null;
private object requestStartMarker = null;
private object requestMethodMarker = null;
private object requestUriMarker = null;
private object requestVersionMarker = null;
private object requestLengthMarker = null;
private object requestEncodingMarker = null;
private object requestContentTypeMarker = null;
private object requestCharsetMarker = null;
private object requestHeadersMarker = null;
private object responseStartMarker = null;
private object responseVersionMarker = null;
private object responseStatusMarker = null;
private object responseLengthMarker = null;
private object responseEncodingMarker = null;
private object responseContentTypeMarker = null;
private object responseCharsetMarker = null;
private object responseHeadersMarker = null;
private object requestBodyMarker = null;
private object responseBodyMarker = null;
private IEnumerator requestHeadersEnum = null;
private IEnumerator responseHeadersEnum = null;
private object stateMarker = null;
private object requestStartMarker = null;
private object requestMethodMarker = null;
private object requestUriMarker = null;
private object requestVersionMarker = null;
private object requestTransferEncodingMarker = null;
private object requestLengthMarker = null;
private object requestContentEncodingMarker = null;
private object requestContentTypeMarker = null;
private object requestCharsetMarker = null;
private object requestHeadersMarker = null;
private object responseStartMarker = null;
private object responseVersionMarker = null;
private object responseStatusMarker = null;
private object responseTransferEncodingMarker = null;
private object responseLengthMarker = null;
private object responseContentEncodingMarker = null;
private object responseContentTypeMarker = null;
private object responseCharsetMarker = null;
private object responseHeadersMarker = null;
private object requestBodyMarker = null;
private object responseBodyMarker = null;
private IEnumerator requestHeadersEnum = null;
private IEnumerator responseHeadersEnum = null;
 
public HttpMessage Http
{
1807,18 → 1809,33
{
}
 
private string EncodingToString(HttpEncoding encoding)
private string EncodingToString(HttpTransferEncoding encoding)
{
switch(encoding)
{
case HttpEncoding.Identify: return "identify";
case HttpEncoding.Gzip: return "gzip";
case HttpEncoding.Compress: return "compress";
case HttpEncoding.Deflate: return "deflate";
default: return "<unknown>";
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>";
}
}
 
protected override void InitView()
{
try
1828,7 → 1845,7
owner.messagesBox.Clear();
 
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Complete: ",
owner.messagesBox.AppendText("Complete: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
stateMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.RequestComplete && http.ResponseComplete ? "YES" : "NO",
1838,7 → 1855,7
owner.messagesBox.AppendNewLine();
 
// request info
owner.messagesBox.AppendText("Request Start: ",
owner.messagesBox.AppendText("Request Start: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestStartMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.RequestStartTimestamp == DateTime.MinValue
1847,7 → 1864,7
owner.messagesBox.EndMark(requestStartMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Request Method: ",
owner.messagesBox.AppendText("Request Method: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestMethodMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.RequestMethod,
1855,7 → 1872,7
owner.messagesBox.EndMark(requestMethodMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Request URI: ",
owner.messagesBox.AppendText("Request URI: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestUriMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.RequestUri,
1863,7 → 1880,7
owner.messagesBox.EndMark(requestUriMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Request Version: ",
owner.messagesBox.AppendText("Request Version: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestVersionMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.RequestVersion == HttpVersion.V0_9 ? "HTTP/0.9"
1872,8 → 1889,16
owner.messagesBox.EndMark(requestVersionMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Request Content Length: ",
owner.messagesBox.AppendText("Request Transfer Encoding: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestTransferEncodingMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(EncodingToString(http.RequestTransferEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(requestTransferEncodingMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Request Content Length: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestLengthMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.RequestLength < 0 ? "<unknown>" : http.RequestLength.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
1880,15 → 1905,15
owner.messagesBox.EndMark(requestLengthMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Request Content Encoding: ",
owner.messagesBox.AppendText("Request Content Encoding: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestEncodingMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(EncodingToString(http.RequestEncoding),
requestContentEncodingMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(EncodingToString(http.RequestContentEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(requestEncodingMarker);
owner.messagesBox.EndMark(requestContentEncodingMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Request Content Type: ",
owner.messagesBox.AppendText("Request Content Type: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestContentTypeMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.RequestContentType == null ? "<unknown>"
1897,7 → 1922,7
owner.messagesBox.EndMark(requestContentTypeMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Request Content Charset: ",
owner.messagesBox.AppendText("Request Content Charset: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
requestCharsetMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.RequestCharset == null ? "<unknown>" : http.RequestCharset,
1916,7 → 1941,7
 
// response info
owner.messagesBox.AppendNewLine();
owner.messagesBox.AppendText("Response Start: ",
owner.messagesBox.AppendText("Response Start: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
responseStartMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.ResponseStartTimestamp == DateTime.MinValue
1925,7 → 1950,7
owner.messagesBox.EndMark(responseStartMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Response Version: ",
owner.messagesBox.AppendText("Response Version: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
responseVersionMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.ResponseVersion == HttpVersion.V0_9
1934,7 → 1959,7
owner.messagesBox.EndMark(responseVersionMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Response Status: ",
owner.messagesBox.AppendText("Response Status: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
responseStatusMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.ResponseStatusCode + " " + http.ResponseStatusMessage,
1942,8 → 1967,16
owner.messagesBox.EndMark(responseStatusMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Response Content Length: ",
owner.messagesBox.AppendText("Response Transfer Encoding: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
responseTransferEncodingMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(EncodingToString(http.ResponseTransferEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(responseTransferEncodingMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Response Content Length: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
responseLengthMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.ResponseLength < 0 ? "<unknown>" : http.ResponseLength.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
1950,15 → 1983,15
owner.messagesBox.EndMark(responseLengthMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Response Content Encoding: ",
owner.messagesBox.AppendText("Response Content Encoding: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
responseEncodingMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(EncodingToString(http.ResponseEncoding),
responseContentEncodingMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(EncodingToString(http.ResponseContentEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.EndMark(responseEncodingMarker);
owner.messagesBox.EndMark(responseContentEncodingMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Response Content Type: ",
owner.messagesBox.AppendText("Response Content Type: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
responseContentTypeMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.ResponseContentType == null ? "<unknown>"
1967,7 → 2000,7
owner.messagesBox.EndMark(responseContentTypeMarker);
owner.messagesBox.AppendNewLine();
 
owner.messagesBox.AppendText("Response Content Charset: ",
owner.messagesBox.AppendText("Response Content Charset: ",
Color.DarkRed, Color.Transparent, false, false, 0, 0);
responseCharsetMarker = owner.messagesBox.BeginMark();
owner.messagesBox.AppendText(http.ResponseCharset == null ? "<unknown>" : http.ResponseCharset,
2018,10 → 2051,12
owner.messagesBox.ChangeText(requestVersionMarker, http.RequestVersion == HttpVersion.V0_9 ? "HTTP/0.9"
: http.RequestVersion == HttpVersion.V1_0 ? "HTTP/1.0" : "HTTP/1.1",
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(requestTransferEncodingMarker, EncodingToString(http.RequestTransferEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(requestLengthMarker, http.RequestLength < 0
? "<unknown>" : http.RequestLength.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(requestEncodingMarker, EncodingToString(http.RequestEncoding),
owner.messagesBox.ChangeText(requestContentEncodingMarker, EncodingToString(http.RequestContentEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(requestContentTypeMarker, http.RequestContentType == null ? "<unknown>"
: http.RequestContentType + "/" + http.RequestContentSubtype,
2037,10 → 2072,12
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(responseStatusMarker, http.ResponseStatusCode + " " + http.ResponseStatusMessage,
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(responseTransferEncodingMarker, EncodingToString(http.ResponseTransferEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(responseLengthMarker, http.ResponseLength < 0
? "<unknown>" : http.ResponseLength.ToString(),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(responseEncodingMarker, EncodingToString(http.ResponseEncoding),
owner.messagesBox.ChangeText(responseContentEncodingMarker, EncodingToString(http.ResponseContentEncoding),
Color.DarkRed, Color.LightGray, false, false, 0, 27);
owner.messagesBox.ChangeText(responseContentTypeMarker, http.ResponseContentType == null ? "<unknown>"
: http.ResponseContentType + "/" + http.ResponseContentSubtype,
2118,16 → 2155,17
{
// request info
writer.WriteLine(
"Complete: " + (http.RequestComplete && http.ResponseComplete ? "YES" : "NO") + "\r\n"
+ "\r\nRequest Method: " + http.RequestMethod
+ "\r\nRequest URI: " + http.RequestUri
+ "\r\nRequest Version: " + (http.RequestVersion == HttpVersion.V0_9 ? "HTTP/0.9"
"Complete: " + (http.RequestComplete && http.ResponseComplete ? "YES" : "NO") + "\r\n"
+ "\r\nRequest Method: " + http.RequestMethod
+ "\r\nRequest URI: " + http.RequestUri
+ "\r\nRequest Version: " + (http.RequestVersion == HttpVersion.V0_9 ? "HTTP/0.9"
: http.RequestVersion == HttpVersion.V1_0 ? "HTTP/1.0" : "HTTP/1.1")
+ "\r\nRequest Content Length: " + (http.RequestLength < 0 ? "<unknown>" : http.RequestLength.ToString())
+ "\r\nRequest Content Encoding: " + EncodingToString(http.RequestEncoding)
+ "\r\nRequest Content Type: " + (http.RequestContentType == null ? "<unknown>"
+ "\r\nRequest Transfer Encoding: " + EncodingToString(http.RequestTransferEncoding)
+ "\r\nRequest Content Length: " + (http.RequestLength < 0 ? "<unknown>" : http.RequestLength.ToString())
+ "\r\nRequest Content Encoding: " + EncodingToString(http.RequestContentEncoding)
+ "\r\nRequest Content Type: " + (http.RequestContentType == null ? "<unknown>"
: http.RequestContentType + "/" + http.RequestContentSubtype)
+ "\r\nRequest Content Charset: " + (http.RequestCharset == null ? "<unknown>" : http.RequestCharset)
+ "\r\nRequest Content Charset: " + (http.RequestCharset == null ? "<unknown>" : http.RequestCharset)
+ "\r\nRequest Headers:");
 
foreach(HttpHeader h in http.RequestHeaders)
2149,15 → 2187,16
 
// response info
writer.WriteLine(
"\r\nResponse Version: " + (http.ResponseVersion == HttpVersion.V0_9
"\r\nResponse Version: " + (http.ResponseVersion == HttpVersion.V0_9
? "HTTP/0.9" : http.ResponseVersion == HttpVersion.V1_0 ? "HTTP/1.0" : "HTTP/1.1")
+ "\r\nResponse Status: " + http.ResponseStatusCode + " " + http.ResponseStatusMessage
+ "\r\nResponse Content Length: " + (http.ResponseLength < 0
+ "\r\nResponse Status: " + http.ResponseStatusCode + " " + http.ResponseStatusMessage
+ "\r\nResponse Transfer Encoding: " + EncodingToString(http.ResponseTransferEncoding)
+ "\r\nResponse Content Length: " + (http.ResponseLength < 0
? "<unknown>" : http.ResponseLength.ToString())
+ "\r\nResponse Content Encoding: " + EncodingToString(http.ResponseEncoding)
+ "\r\nResponse Content Type: " + (http.ResponseContentType == null ? "<unknown>"
+ "\r\nResponse Content Encoding: " + EncodingToString(http.ResponseContentEncoding)
+ "\r\nResponse Content Type: " + (http.ResponseContentType == null ? "<unknown>"
: http.ResponseContentType + "/" + http.ResponseContentSubtype)
+ "\r\nResponse Content Charset: " + (http.ResponseCharset == null ? "<unknown>" : http.ResponseCharset)
+ "\r\nResponse Content Charset: " + (http.ResponseCharset == null ? "<unknown>" : http.ResponseCharset)
+ "\r\nResponse Headers:");
 
foreach(HttpHeader h in http.ResponseHeaders)
/TCPproxy/trunk/Network.cs
11,7 → 11,11
// FIXME deny write access to all public properties
// FIXME for text/xml get encoding from body if not specified in header
// FIXME option to not store parsed data, just raw packets and reparse on demand
// FIXME implement chunk-encoding
// FIXME implement all others (not 'identity' and 'chunked') transfer-encodings
// FIXME benchmark one-by-one byte iterator vs. block read
// FIXME recongize "100 (Continue)" response, use next (real) response as part of same
// request-response interaction
// FIXME split HttpMessage class to request and response
namespace TCPproxy
{
public enum BinLogTypes
54,9 → 58,11
V1_1
}
 
public enum HttpEncoding
public enum HttpTransferEncoding
{
Identify,
None, // there is no body
Identity,
Chunked,
Gzip,
Compress,
Deflate,
63,6 → 69,16
Unknown
}
 
public enum HttpContentEncoding
{
None, // there is no body
Identity,
Gzip,
Compress,
Deflate,
Unknown
}
 
public class TcpLogEventArgs : EventArgs
{
private readonly LogLevel level;
407,11 → 423,6
}
}
 
public override string ToString() // FIXME delete the method
{
return id + " " + startTimestamp.ToString("HH:mm:ss.ffff");
}
 
protected void SetLocalPoint(IPEndPoint localPoint)
{
this.localPoint = localPoint;
1382,17 → 1393,14
{
tcp = newTcp;
tcpLen = tcp.Length;
tcpPos = 0;
tcpPos = -1;
if(nextMessageEvent != null) nextMessageEvent.Set();
}
}
 
public byte CurrentOctet()
public void Back()
{
if(tcp == null || tcpPos >= tcpLen) NextTcp();
if(tcpEnd) return 0;
 
return tcp.Bytes[tcpPos];
tcpPos--; // FIXME double check if it's always possible to go to _one_ step back
}
 
public byte NextOctet()
1399,12 → 1407,24
{
tcpPos++;
 
if(tcp == null || tcpPos >= tcpLen) NextTcp();
if(tcp == null || tcpPos >= tcpLen)
{
NextTcp();
tcpPos++;
}
if(tcpEnd) return 0;
 
return tcp.Bytes[tcpPos];
}
 
public byte NextOctetAndBack()
{
byte b = NextOctet();
if(!tcpEnd) Back();
 
return b;
}
 
public void SetDirection(TcpMessageDirection direction)
{
do
1422,7 → 1442,7
if(!tcpEnd)
{
tcpLen = tcp.Length;
tcpPos = 0;
tcpPos = -1;
}
}
}
1500,7 → 1520,7
SetRequestProperties(http);
http.UpdateHttpMessage();
 
bool fullLength = ParseBody(requestPos, http, true);
ParseBody(requestPos, http, true);
if("text" == http.RequestContentType && "xml" == http.RequestContentSubtype)
{
http.RequestXml = new XmlMessage(http.RequestText);
1507,7 → 1527,6
}
http.UpdateHttpMessage();
 
if(fullLength) requestPos.NextOctet();
http.RequestComplete = true;
http.UpdateHttpMessage();
 
1566,7 → 1585,7
SetResponseProperties(http);
http.UpdateHttpMessage();
 
bool fullLength = ParseBody(responsePos, http, false);
ParseBody(responsePos, http, false);
if("text" == http.ResponseContentType && "xml" == http.ResponseContentSubtype)
{
http.ResponseXml = new XmlMessage(http.ResponseText);
1573,7 → 1592,6
}
http.UpdateHttpMessage();
 
if(fullLength) responsePos.NextOctet();
http.ResponseComplete = true;
http.UpdateHttpMessage();
}
1589,11 → 1607,12
StringBuilder res = new StringBuilder(100);
int len = 0;
 
for(byte b = pos.CurrentOctet(); !pos.IsEnd && tokenChars[b]; b = pos.NextOctet())
for(byte b = pos.NextOctet(); !pos.IsEnd && tokenChars[b]; b = pos.NextOctet())
{
res.Append(charValues[b]);
if(limit > 0 && limit < ++len) return null; // length limit
}
pos.Back();
 
return res.ToString();
}
1603,11 → 1622,12
StringBuilder res = new StringBuilder(1024);
int len = 0;
 
for(byte b = pos.CurrentOctet(); !pos.IsEnd && b != 32 && b != 13 && b != 10; b = pos.NextOctet())
for(byte b = pos.NextOctet(); !pos.IsEnd && b != 32 && b != 13 && b != 10; b = pos.NextOctet())
{ // <space> <cr> <lf>
res.Append(charValues[b]);
if(limit > 0 && limit < ++len) return null; // length limit
}
pos.Back();
 
return res.ToString();
}
1617,11 → 1637,12
StringBuilder res = new StringBuilder(1024);
int len = 0;
 
for(byte b = pos.CurrentOctet(); !pos.IsEnd && b != 13; b = pos.NextOctet())
for(byte b = pos.NextOctet(); !pos.IsEnd && b != 13; b = pos.NextOctet())
{ // <cr>
res.Append(charValues[b]);
if(limit > 0 && limit < ++len) return null; // length limit
}
pos.Back();
 
return res.ToString();
}
1628,26 → 1649,24
 
private void ExpectSpace(ParsePosition pos)
{
if(pos.IsEnd || pos.CurrentOctet() != 32)
if(pos.IsEnd || pos.NextOctet() != 32)
throw new HttpParseException("Space expected");
 
pos.NextOctet();
}
 
private void ExpectCRLF(ParsePosition pos)
{
if(pos.IsEnd || pos.CurrentOctet() != 13)
if(pos.IsEnd || pos.NextOctet() != 13)
throw new HttpParseException("Carriage return expected");
if(pos.IsEnd || pos.NextOctet() != 10)
throw new HttpParseException("Linefeed expected");
 
pos.NextOctet();
}
 
private void SkipEmptyLines(ParsePosition pos)
{
while(pos.CurrentOctet() == 13)
while(pos.NextOctetAndBack() == 13)
{
ExpectCRLF(pos);
}
}
 
private void ParseRequestLine(ParsePosition pos, HttpMessage http)
1667,25 → 1686,17
throw new HttpParseException("Unexpected end of message");
 
// EoL or version
byte b = pos.CurrentOctet();
byte b = pos.NextOctet();
if(b == 13)
{
if(pos.IsEnd || pos.NextOctet() != 10)
{
throw new HttpParseException("Linefeed expected");
}
else
{
if(!pos.IsEnd) ExpectCRLF(pos);
http.RequestVersion = HttpVersion.V0_9;
return;
}
pos.Back();
ExpectCRLF(pos);
http.RequestVersion = HttpVersion.V0_9;
}
else if(b != 32)
{
throw new HttpParseException("HTTP version expected");
}
pos.NextOctet();
 
// check version
string versionStr = GetUntilEoL(pos, 20);
1717,17 → 1728,10
if(pos.IsEnd)
throw new HttpParseException("Unexpected end of message");
 
if(pos.CurrentOctet() == 13)
if(pos.NextOctetAndBack() == 13)
{
if(pos.IsEnd || pos.NextOctet() != 10)
{
throw new HttpParseException("Linefeed expected");
}
else
{
pos.NextOctet(); // end of header, move to body
return;
}
ExpectCRLF(pos);
return; // end of header, move to body
}
if(pos.IsEnd) return; // end of TCP messages
 
1735,10 → 1739,9
if(name == null || name.Length == 0)
throw new HttpParseException("Request header name expected");
 
if(pos.IsEnd || pos.CurrentOctet() != 58) // :
if(pos.IsEnd || pos.NextOctet() != 58) // :
throw new HttpParseException("Request header value expected");
 
pos.NextOctet();
string s = TrimHeaderValue(GetUntilEoL(pos, 0));
 
ExpectCRLF(pos);
1838,34 → 1841,59
return buf.ToString();
}
 
private HttpEncoding ParseEncoding(string encoding)
private HttpTransferEncoding ParseTransferEncoding(string encoding)
{
if(encoding == null || encoding == "identity")
return HttpEncoding.Identify;
if(encoding == null) return HttpTransferEncoding.None;
encoding = encoding.ToLower();
 
if(encoding == "identity")
return HttpTransferEncoding.Identity;
else if(encoding == "chunked")
return HttpTransferEncoding.Chunked;
else if(encoding == "gzip")
return HttpEncoding.Gzip;
return HttpTransferEncoding.Gzip;
else if(encoding == "compress")
return HttpEncoding.Compress;
return HttpTransferEncoding.Compress;
else if(encoding == "deflate")
return HttpEncoding.Deflate;
return HttpTransferEncoding.Deflate;
else
return HttpEncoding.Unknown;
return HttpTransferEncoding.Unknown;
}
 
private HttpContentEncoding ParseContentEncoding(string encoding)
{
if(encoding == null) return HttpContentEncoding.None;
encoding = encoding.ToLower();
 
if(encoding == "identity")
return HttpContentEncoding.Identity;
else if(encoding == "gzip")
return HttpContentEncoding.Gzip;
else if(encoding == "compress")
return HttpContentEncoding.Compress;
else if(encoding == "deflate")
return HttpContentEncoding.Deflate;
else
return HttpContentEncoding.Unknown;
}
 
private void SetRequestProperties(HttpMessage http)
{
// length
string contentLength = (string)http.RequestHeadersHash["Content-Length"];
string contentLength = (string)http.RequestHeadersHash["content-length"];
if(contentLength != null)
{
http.RequestLength = int.Parse(contentLength);
}
 
// encoding
http.RequestEncoding = ParseEncoding((string)http.RequestHeadersHash["Content-Encoding"]);
// transfer encoding
http.RequestTransferEncoding = ParseTransferEncoding((string)http.RequestHeadersHash["transfer-encoding"]);
 
// content encoding
http.RequestContentEncoding = ParseContentEncoding((string)http.RequestHeadersHash["content-encoding"]);
 
// type & charset
string contentType = (string)http.RequestHeadersHash["Content-Type"];
string contentType = (string)http.RequestHeadersHash["content-type"];
if(contentType != null)
{
Match match = Regex.Match(contentType, @"^\s*(\S+)/(\S+)\s*($|;\s*(charset=""?(\S+)""?)?)");
1885,22 → 1913,76
}
}
 
private bool ParseBody(ParsePosition pos, HttpMessage http, bool request)
// RFC 2616: 4.3
private bool WaitForBody(HttpMessage http, bool isRequest)
{
if(request && http.RequestMethod != "POST") return false;
if(isRequest)
{
return (http.RequestLength > 0)
|| (http.RequestTransferEncoding != HttpTransferEncoding.None);
}
else
{
if(http.RequestMethod == "HEAD") return false;
if(http.ResponseStatusCode < 200) return false;
if(http.ResponseStatusCode == 204) return false;
if(http.ResponseStatusCode == 304) return false;
 
return true;
}
}
 
private void ParseBody(ParsePosition pos, HttpMessage http, bool isRequest)
{
if(!WaitForBody(http, isRequest)) return;
 
// FIXME parse and save on-the-fly, dont wait util end of message
 
byte[] bin = new byte[8*1024];
int len = 0;
int limit = (request ? http.RequestLength : http.ResponseLength);
HttpEncoding encoding = (request ? http.RequestEncoding : http.ResponseEncoding);
string contentType = (request ? http.RequestContentType : http.ResponseContentType);
string contentSubtype = (request ? http.RequestContentSubtype : http.ResponseContentSubtype);
string charset = (request ? http.RequestCharset : http.ResponseCharset);
byte[] bin = new byte[8*1024];
int len = 0; // current bin biffer length
int limit = (isRequest ? http.RequestLength : http.ResponseLength);
int chunkLen = -1; // current length of current chunk
int chunkLimit = -1;
HttpTransferEncoding transferEncoding = (isRequest ? http.RequestTransferEncoding : http.ResponseTransferEncoding);
HttpContentEncoding contentEncoding = (isRequest ? http.RequestContentEncoding : http.ResponseContentEncoding);
string contentType = (isRequest ? http.RequestContentType : http.ResponseContentType);
string contentSubtype = (isRequest ? http.RequestContentSubtype : http.ResponseContentSubtype);
string charset = (isRequest ? http.RequestCharset : http.ResponseCharset);
 
for(byte b = pos.CurrentOctet(); !pos.IsEnd; b = pos.NextOctet())
for(byte b = pos.NextOctet(); !pos.IsEnd; b = pos.NextOctet())
{
// RFC 2616: 3.6.1
if(transferEncoding == HttpTransferEncoding.Chunked && chunkLimit < 0)
{
// FIXME recognize chunk-extension here
 
// get chunk length
pos.Back();
string chunkLimitStr = GetUntilEoL(pos, 40);
if(pos.IsEnd || chunkLimitStr == null || chunkLimitStr.Length == 0)
throw new HttpParseException("Chunk length expected");
 
try
{
chunkLimit = Convert.ToInt32(chunkLimitStr, 16);
}
catch(Exception)
{
throw new HttpParseException("Cannot parse chunk length");
}
 
ExpectCRLF(pos);
 
if(chunkLimit == 0) { // the end marker
ExpectCRLF(pos);
break;
}
 
chunkLen = 0;
b = pos.NextOctet();
}
 
// grow array if full
if(len >= bin.Length)
{
byte[] newBin = new byte[bin.Length*2];
1909,14 → 1991,32
}
 
bin[len++] = b;
if(limit > 0 && limit <= len) // full length
chunkLen++;
if(chunkLimit > 0)
{
break;
if(chunkLen >= chunkLimit) // full chunk
{
ExpectCRLF(pos);
chunkLimit = -1; // try to find length of next chunk on next iteration
}
}
else
{
if(limit > 0 && len >= limit) // full length
{
break;
}
}
}
if(transferEncoding == HttpTransferEncoding.Chunked && chunkLimit > 0 && chunkLen != chunkLimit)
{
throw new HttpParseException("Incomplete chunk found");
}
 
// FIXME parse entity-headers for chunked encoding here
 
string text = null;
if(encoding == HttpEncoding.Identify && contentType == "text")
if(contentEncoding == HttpContentEncoding.Identity && contentType == "text")
{
try
{
1925,11 → 2025,11
}
catch(NotSupportedException)
{
Console.WriteLine("Unsupported encoding: " + charset);
Console.WriteLine("Unsupported charset: " + charset);
}
}
 
if(request)
if(isRequest)
{
http.RequestLength = len;
http.RequestBody = bin;
1941,8 → 2041,6
http.ResponseBody = bin;
http.ResponseText = text;
}
 
return (limit > 0 && limit <= len); // full length reached, need to go to next octet
}
 
private void ParseResponseLine(ParsePosition pos, HttpMessage http)
1995,18 → 2093,22
private void SetResponseProperties(HttpMessage http)
{
// length
HttpHeader contentLength = (HttpHeader)http.ResponseHeadersHash["Content-Length"];
HttpHeader contentLength = (HttpHeader)http.ResponseHeadersHash["content-length"];
if(contentLength != null)
{
http.ResponseLength = int.Parse(contentLength.Values[0]);
}
 
// encoding
HttpHeader contentEncoding = (HttpHeader)http.ResponseHeadersHash["Content-Encoding"];
http.ResponseEncoding = ParseEncoding((contentEncoding == null) ? null : contentEncoding.Values[0]);
// transfer encoding
HttpHeader transferEncoding = (HttpHeader)http.ResponseHeadersHash["transfer-encoding"];
http.ResponseTransferEncoding = ParseTransferEncoding((transferEncoding == null) ? null : transferEncoding.Values[0]);
 
// content encoding
HttpHeader contentEncoding = (HttpHeader)http.ResponseHeadersHash["content-encoding"];
http.ResponseContentEncoding = ParseContentEncoding((contentEncoding == null) ? null : contentEncoding.Values[0]);
 
// type & charset
HttpHeader contentType = (HttpHeader)http.ResponseHeadersHash["Content-Type"];
HttpHeader contentType = (HttpHeader)http.ResponseHeadersHash["content-type"];
if(contentType != null)
{
Match match = Regex.Match(contentType.Values[0], @"^\s*(\S+)/(\S+)\s*($|;\s*(charset=""?(\S+)""?)?)");
2065,38 → 2167,40
 
public class HttpMessage
{
private bool requestComplete = false;
private HttpVersion requestVersion;
private string requestMethod;
private string requestUri;
private LinkedList requestHeaders = new LinkedList();
private Hashtable requestHeadersHash = new Hashtable();
private int requestLength = -1; // -1 == unknown
private HttpEncoding requestEncoding = HttpEncoding.Identify;
private string requestContentType;
private string requestContentSubtype;
private string requestCharset;
private string soapAction;
private byte[] requestBody;
private string requestText;
private XmlMessage requestXml;
private DateTime requestStartTimestamp = DateTime.MinValue;
private bool requestComplete = false;
private HttpVersion requestVersion;
private string requestMethod;
private string requestUri;
private LinkedList requestHeaders = new LinkedList();
private Hashtable requestHeadersHash = new Hashtable();
private int requestLength = -1; // -1 == unknown
private HttpTransferEncoding requestTransferEncoding = HttpTransferEncoding.None;
private HttpContentEncoding requestContentEncoding = HttpContentEncoding.None;
private string requestContentType;
private string requestContentSubtype;
private string requestCharset;
private string soapAction;
private byte[] requestBody;
private string requestText;
private XmlMessage requestXml;
private DateTime requestStartTimestamp = DateTime.MinValue;
 
private bool responseComplete = false;
private HttpVersion responseVersion;
private int responseStatusCode;
private string responseStatusMessage;
private LinkedList responseHeaders = new LinkedList();
private Hashtable responseHeadersHash = new Hashtable();
private int responseLength = -1; // -1 == unknown
private HttpEncoding responseEncoding = HttpEncoding.Identify;
private string responseContentType;
private string responseContentSubtype;
private string responseCharset;
private byte[] responseBody;
private string responseText;
private XmlMessage responseXml;
private DateTime responseStartTimestamp = DateTime.MinValue;
private bool responseComplete = false;
private HttpVersion responseVersion;
private int responseStatusCode;
private string responseStatusMessage;
private LinkedList responseHeaders = new LinkedList();
private Hashtable responseHeadersHash = new Hashtable();
private int responseLength = -1; // -1 == unknown
private HttpTransferEncoding responseTransferEncoding = HttpTransferEncoding.None;
private HttpContentEncoding responseContentEncoding = HttpContentEncoding.None;
private string responseContentType;
private string responseContentSubtype;
private string responseCharset;
private byte[] responseBody;
private string responseText;
private XmlMessage responseXml;
private DateTime responseStartTimestamp = DateTime.MinValue;
 
public bool RequestComplete
{
2138,12 → 2242,18
set { requestLength = value; }
}
 
public HttpEncoding RequestEncoding
public HttpTransferEncoding RequestTransferEncoding
{
get { return requestEncoding; }
set { requestEncoding = value; }
get { return requestTransferEncoding; }
set { requestTransferEncoding = value; }
}
 
public HttpContentEncoding RequestContentEncoding
{
get { return requestContentEncoding; }
set { requestContentEncoding = value; }
}
 
public string RequestContentType
{
get { return requestContentType; }
2232,12 → 2342,18
set { responseLength = value; }
}
 
public HttpEncoding ResponseEncoding
public HttpTransferEncoding ResponseTransferEncoding
{
get { return responseEncoding; }
set { responseEncoding = value; }
get { return responseTransferEncoding; }
set { responseTransferEncoding = value; }
}
 
public HttpContentEncoding ResponseContentEncoding
{
get { return responseContentEncoding; }
set { responseContentEncoding = value; }
}
 
public string ResponseContentType
{
get { return responseContentType; }
2283,7 → 2399,7
public void AddRequestHeader(string name, string headerValue)
{
requestHeaders.Add(new HttpHeader(name, headerValue));
requestHeadersHash.Add(name, headerValue);
requestHeadersHash.Add(name.ToLower(), headerValue);
}
 
public void AddResponseHeader(string name, string headerValue)
2293,7 → 2409,7
{
header = new HttpHeader(name, headerValue);
responseHeaders.Add(header);
responseHeadersHash.Add(name, header);
responseHeadersHash.Add(name.ToLower(), header);
}
else
{
2301,12 → 2417,6
}
}
 
public override string ToString() // FIXME delete the method
{
return (soapAction != null ? soapAction
: (requestMethod == null ? "" : requestMethod) + " " + (requestUri == null ? "" : requestUri));
}
 
public event TcpEventHandler Update;
 
protected virtual void OnUpdate(TcpEventArgs e)