/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) |