Commit cc0fd15f authored by Brickner_cp's avatar Brickner_cp

HTTP

parent fffd905c
...@@ -90,6 +90,11 @@ namespace PcapDotNet.Base ...@@ -90,6 +90,11 @@ namespace PcapDotNet.Base
return sequence.SequenceToString(separator, string.Empty); return sequence.SequenceToString(separator, string.Empty);
} }
public static string SequenceToString<T>(this IEnumerable<T> sequence, char separator)
{
return sequence.SequenceToString(separator.ToString());
}
/// <summary> /// <summary>
/// Converts a sequence to a string by converting each element to a string. /// Converts a sequence to a string by converting each element to a string.
/// </summary> /// </summary>
......
...@@ -13,6 +13,7 @@ using PcapDotNet.Packets; ...@@ -13,6 +13,7 @@ using PcapDotNet.Packets;
using PcapDotNet.Packets.Arp; using PcapDotNet.Packets.Arp;
using PcapDotNet.Packets.Ethernet; using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Gre; using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.Icmp; using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.Igmp; using PcapDotNet.Packets.Igmp;
using PcapDotNet.Packets.IpV4; using PcapDotNet.Packets.IpV4;
...@@ -31,6 +32,10 @@ namespace PcapDotNet.Core.Test ...@@ -31,6 +32,10 @@ namespace PcapDotNet.Core.Test
private const string WiresharkDiretory = @"C:\Program Files\Wireshark\"; private const string WiresharkDiretory = @"C:\Program Files\Wireshark\";
private const string WiresharkTsharkPath = WiresharkDiretory + @"tshark.exe"; private const string WiresharkTsharkPath = WiresharkDiretory + @"tshark.exe";
private const bool IsRetry
// = true;
= false;
/// <summary> /// <summary>
/// Gets or sets the test context which provides /// Gets or sets the test context which provides
/// information about and functionality for the current test run. /// information about and functionality for the current test run.
...@@ -201,9 +206,6 @@ namespace PcapDotNet.Core.Test ...@@ -201,9 +206,6 @@ namespace PcapDotNet.Core.Test
private static void ComparePacketsToWireshark(IEnumerable<Packet> packets) private static void ComparePacketsToWireshark(IEnumerable<Packet> packets)
{ {
string pcapFilename = Path.GetTempPath() + "temp." + new Random().NextByte() + ".pcap"; string pcapFilename = Path.GetTempPath() + "temp." + new Random().NextByte() + ".pcap";
const bool IsRetry
// = true;
= false;
#pragma warning disable 162 #pragma warning disable 162
// ReSharper disable ConditionIsAlwaysTrueOrFalse // ReSharper disable ConditionIsAlwaysTrueOrFalse
// ReSharper disable HeuristicUnreachableCode // ReSharper disable HeuristicUnreachableCode
...@@ -216,7 +218,10 @@ namespace PcapDotNet.Core.Test ...@@ -216,7 +218,10 @@ namespace PcapDotNet.Core.Test
const byte RetryNumber = 89; const byte RetryNumber = 89;
pcapFilename = Path.GetTempPath() + "temp." + RetryNumber + ".pcap"; pcapFilename = Path.GetTempPath() + "temp." + RetryNumber + ".pcap";
List<Packet> packetsList = new List<Packet>(); List<Packet> packetsList = new List<Packet>();
new OfflinePacketDevice(pcapFilename).Open().ReceivePackets(1000, packetsList.Add); using (PacketCommunicator communicator = new OfflinePacketDevice(pcapFilename).Open())
{
communicator.ReceivePackets(-1, packetsList.Add);
}
packets = packetsList; packets = packetsList;
} }
// ReSharper restore HeuristicUnreachableCode // ReSharper restore HeuristicUnreachableCode
...@@ -378,6 +383,16 @@ namespace PcapDotNet.Core.Test ...@@ -378,6 +383,16 @@ namespace PcapDotNet.Core.Test
} }
break; break;
case "http":
PropertyInfo httpProperty = currentDatagram.GetType().GetProperty("Http");
if (httpProperty == null)
break;
{
currentDatagram = httpProperty.GetValue(currentDatagram);
CompareHttp(layer, (HttpDatagram)currentDatagram);
}
break;
default: default:
return; return;
} }
...@@ -1340,5 +1355,158 @@ namespace PcapDotNet.Core.Test ...@@ -1340,5 +1355,158 @@ namespace PcapDotNet.Core.Test
MoreAssert.AreSequenceEqual(optionShows, option.GetWiresharkSubfieldStrings()); MoreAssert.AreSequenceEqual(optionShows, option.GetWiresharkSubfieldStrings());
} }
} }
private static void CompareHttp(XElement httpElement, HttpDatagram httpDatagram)
{
string httpFieldName;
StringBuilder data = new StringBuilder();
bool isFirstEmptyName = true;
foreach (var field in httpElement.Fields())
{
if (field.Name() == "data" || field.Name() == "data.data")
{
if (field.Name() == "data")
field.AssertNoShow();
string previousData = data.ToString();
for (int i = 0; i != previousData.Length / 2; ++i)
{
byte value = Convert.ToByte(previousData.Substring(i * 2, 2), 16);
Assert.AreEqual(httpDatagram[i], value);
}
field.AssertValue(httpDatagram.Skip(previousData.Length / 2), field.Name());
continue;
}
string fieldShow = field.Show();
switch (field.Name())
{
case "http.request":
field.AssertShowDecimal(httpDatagram.IsRequest);
break;
case "http.response":
field.AssertShowDecimal(httpDatagram.IsResponse);
break;
case "":
data.Append(field.Value());
if (fieldShow == @"\r\n")
break;
else if (isFirstEmptyName)
{
CompareHttpFirstLine(field, httpDatagram);
isFirstEmptyName = false;
}
else if (fieldShow.StartsWith("Content-encoded entity body"))
{
break;
}
else if (fieldShow == "HTTP chunked response")
{
field.AssertValue(httpDatagram.Body);
}
else
{
int colonIndex = fieldShow.IndexOf(':');
MoreAssert.IsBiggerOrEqual(0, colonIndex, "Can't find colon in field with empty name");
if (httpDatagram.Header == null)
{
Assert.IsTrue(httpDatagram.IsRequest);
Assert.IsNull(httpDatagram.Version);
break;
}
httpFieldName = fieldShow.Substring(0, colonIndex);
string fieldValue = fieldShow.Substring(colonIndex + 1).SkipWhile(c => c == ' ').TakeWhile(c => c != '\\').SequenceToString();
string expectedFieldValue = httpDatagram.Header[httpFieldName].ValueString;
Assert.IsTrue(expectedFieldValue.Contains(fieldValue),
string.Format("{0} <{1}> doesn't contain <{2}>", field.Name(), expectedFieldValue, fieldValue));
}
break;
case "data.len":
field.AssertShowDecimal(httpDatagram.Length - data.Length / 2);
break;
case "http.host":
case "http.user_agent":
case "http.accept":
case "http.accept_language":
case "http.accept_encoding":
case "http.connection":
case "http.cookie":
case "http.cache_control":
case "http.content_encoding":
case "http.date":
case "http.referer":
case "http.last_modified":
case "http.server":
case "http.set_cookie":
case "http.location":
httpFieldName = field.Name().Substring(5).Replace('_', '-');
HttpField httpField = httpDatagram.Header[httpFieldName];
if (!field.Value().EndsWith("0d0a"))
Assert.IsNull(httpField);
else
{
string fieldValue = field.Show().Replace("\\\"", "\"");
string expectedFieldValue = httpField.ValueString;
Assert.IsTrue(expectedFieldValue.Contains(fieldValue),
string.Format("{0} <{1}> doesn't contain <{2}>", field.Name(), expectedFieldValue, fieldValue));
}
break;
case "http.content_length_header":
field.AssertShowDecimal(httpDatagram.Header.ContentLength.ContentLength.Value);
break;
case "http.content_type":
string[] mediaType = fieldShow.Split(new[] {';', ' ', '/'}, StringSplitOptions.RemoveEmptyEntries);
Assert.AreEqual(httpDatagram.Header.ContentType.MediaType, mediaType[0]);
Assert.AreEqual(httpDatagram.Header.ContentType.MediaSubType, mediaType[1]);
MoreAssert.AreSequenceEqual(httpDatagram.Header.ContentType.Parameters.Select(pair => pair.Key + '=' + pair.Value), mediaType.Skip(2));
break;
case "http.transfer_encoding":
field.AssertShow(httpDatagram.Header.TransferEncoding.TransferCodings.SequenceToString(','));
break;
default:
throw new InvalidOperationException("Invalid HTTP field " + field.Name());
}
}
}
private static void CompareHttpFirstLine(XElement httpFirstLineElement, HttpDatagram httpDatagram)
{
foreach (var field in httpFirstLineElement.Fields())
{
switch (field.Name())
{
case "http.request.method":
Assert.IsTrue(httpDatagram.IsRequest, field.Name() + " IsRequest");
field.AssertShow(((HttpRequestDatagram)httpDatagram).Method);
break;
case "http.request.uri":
Assert.IsTrue(httpDatagram.IsRequest, field.Name() + " IsRequest");
field.AssertShow(((HttpRequestDatagram)httpDatagram).Uri);
break;
case "http.request.version":
field.AssertShow(httpDatagram.Version.ToString());
break;
case "http.response.code":
Assert.IsTrue(httpDatagram.IsResponse, field.Name() + " IsResponse");
field.AssertShowDecimal(((HttpResponseDatagram)httpDatagram).StatusCode.Value);
break;
default:
throw new InvalidOperationException("Invalid HTTP first line field " + field.Name());
}
}
}
} }
} }
\ No newline at end of file
...@@ -47,6 +47,11 @@ namespace PcapDotNet.Core.Test ...@@ -47,6 +47,11 @@ namespace PcapDotNet.Core.Test
Assert.AreEqual(element.Name(), expectedName); Assert.AreEqual(element.Name(), expectedName);
} }
public static void AssertNoShow(this XElement element)
{
Assert.IsNull(element.Attribute("show"));
}
public static void AssertShow(this XElement element, string expectedValue, string message = null) public static void AssertShow(this XElement element, string expectedValue, string message = null)
{ {
Assert.AreEqual(expectedValue, element.Show(), message ?? element.Name()); Assert.AreEqual(expectedValue, element.Show(), message ?? element.Name());
...@@ -134,7 +139,7 @@ namespace PcapDotNet.Core.Test ...@@ -134,7 +139,7 @@ namespace PcapDotNet.Core.Test
public static void AssertValue(this XElement element, string expectedValue, string message = null) public static void AssertValue(this XElement element, string expectedValue, string message = null)
{ {
Assert.AreEqual(element.Value(), expectedValue, message ?? element.Name()); Assert.AreEqual(expectedValue, element.Value(), message ?? element.Name());
} }
public static void AssertValue(this XElement element, IEnumerable<byte> expectedValue, string message = null) public static void AssertValue(this XElement element, IEnumerable<byte> expectedValue, string message = null)
......
...@@ -73,6 +73,13 @@ namespace PcapDotNet.Packets.Http ...@@ -73,6 +73,13 @@ namespace PcapDotNet.Packets.Http
public string Name { get; private set; } public string Name { get; private set; }
public ReadOnlyCollection<byte> Value { get; private set; } public ReadOnlyCollection<byte> Value { get; private set; }
public string ValueString
{
get
{
return _defaultEncoding.GetString(Value.ToArray());
}
}
public virtual bool Equals(HttpField other) public virtual bool Equals(HttpField other)
{ {
...@@ -86,12 +93,7 @@ namespace PcapDotNet.Packets.Http ...@@ -86,12 +93,7 @@ namespace PcapDotNet.Packets.Http
public override string ToString() public override string ToString()
{ {
return string.Format("{0}: {1}", Name, ValueToString()); return string.Format("{0}: {1}", Name, ValueString);
}
protected virtual string ValueToString()
{
return _defaultEncoding.GetString(Value.ToArray());
} }
private static readonly Encoding _defaultEncoding = Encoding.GetEncoding(28591); private static readonly Encoding _defaultEncoding = Encoding.GetEncoding(28591);
......
...@@ -20,6 +20,11 @@ namespace PcapDotNet.Packets.Http ...@@ -20,6 +20,11 @@ namespace PcapDotNet.Packets.Http
{ {
} }
public HttpField this[string fieldName]
{
get { return GetField<HttpField>(fieldName); }
}
public HttpTransferEncodingField TransferEncoding public HttpTransferEncodingField TransferEncoding
{ {
get get
...@@ -28,14 +33,6 @@ namespace PcapDotNet.Packets.Http ...@@ -28,14 +33,6 @@ namespace PcapDotNet.Packets.Http
} }
} }
private T GetField<T>(string fieldName) where T : HttpField
{
HttpField field;
if (!_fields.TryGetValue(fieldName, out field))
return null;
return (T)field;
}
public HttpContentLengthField ContentLength public HttpContentLengthField ContentLength
{ {
get get
...@@ -97,6 +94,14 @@ namespace PcapDotNet.Packets.Http ...@@ -97,6 +94,14 @@ namespace PcapDotNet.Packets.Http
_fields = mergedFields.ToDictionary(field => field.Key, field => HttpField.CreateField(field.Key, field.Value.ToArray()), StringComparer.InvariantCultureIgnoreCase); _fields = mergedFields.ToDictionary(field => field.Key, field => HttpField.CreateField(field.Key, field.Value.ToArray()), StringComparer.InvariantCultureIgnoreCase);
} }
private T GetField<T>(string fieldName) where T : HttpField
{
HttpField field;
if (!_fields.TryGetValue(fieldName, out field))
return null;
return (T)field;
}
private static readonly HttpHeader _empty = new HttpHeader(); private static readonly HttpHeader _empty = new HttpHeader();
private readonly Dictionary<string, HttpField> _fields = new Dictionary<string, HttpField>(StringComparer.InvariantCultureIgnoreCase); private readonly Dictionary<string, HttpField> _fields = new Dictionary<string, HttpField>(StringComparer.InvariantCultureIgnoreCase);
} }
......
...@@ -59,10 +59,10 @@ namespace PcapDotNet.Packets.Http ...@@ -59,10 +59,10 @@ namespace PcapDotNet.Packets.Http
SetTransferCodings(match.GroupCapturesValues(RegexTransferCodingGroupName).ToArray()); SetTransferCodings(match.GroupCapturesValues(RegexTransferCodingGroupName).ToArray());
} }
protected override string ValueToString() // protected override string ValueToString()
{ // {
return TransferCodings == null ? string.Empty : TransferCodings.SequenceToString(","); // return TransferCodings == null ? string.Empty : TransferCodings.SequenceToString(",");
} // }
private ReadOnlyCollection<string> _transferCodings; private ReadOnlyCollection<string> _transferCodings;
......
...@@ -29,9 +29,9 @@ namespace PcapDotNet.TestUtils ...@@ -29,9 +29,9 @@ namespace PcapDotNet.TestUtils
"> Actual: <" + actual + ">. " + message); "> Actual: <" + actual + ">. " + message);
} }
public static void IsBiggerOrEqual<T>(T expectedMaximum, T actual) where T : IComparable<T> public static void IsBiggerOrEqual<T>(T expectedMinimum, T actual) where T : IComparable<T>
{ {
IsBiggerOrEqual(expectedMaximum, actual, string.Empty); IsBiggerOrEqual(expectedMinimum, actual, string.Empty);
} }
public static void IsSmallerOrEqual<T>(T expectedMaximum, T actual, string message) where T : IComparable<T> public static void IsSmallerOrEqual<T>(T expectedMaximum, T actual, string message) where T : IComparable<T>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment