Commit d6b96212 authored by Brickner_cp's avatar Brickner_cp

HTTP

parent 339451bf
using System;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.TestUtils;
using PcapDotNet.Packets.Transport;
namespace PcapDotNet.Packets.Test
{
/// <summary>
/// Summary description for HttpTests
/// </summary>
[TestClass]
public class HttpTests
{
/// <summary>
/// Gets or sets the test context which provides
/// information about and functionality for the current test run.
/// </summary>
public TestContext TestContext { get; set; }
#region Additional test attributes
//
// You can use the following additional attributes as you write your tests:
//
// Use ClassInitialize to run code before running the first test in the class
// [ClassInitialize()]
// public static void MyClassInitialize(TestContext testContext) { }
//
// Use ClassCleanup to run code after all tests in a class have run
// [ClassCleanup()]
// public static void MyClassCleanup() { }
//
// Use TestInitialize to run code before running each test
// [TestInitialize()]
// public void MyTestInitialize() { }
//
// Use TestCleanup to run code after each test has run
// [TestCleanup()]
// public void MyTestCleanup() { }
//
#endregion
[TestMethod]
public void RandomHttpTest()
{
MacAddress ethernetSource = new MacAddress("00:01:02:03:04:05");
MacAddress ethernetDestination = new MacAddress("A0:A1:A2:A3:A4:A5");
EthernetLayer ethernetLayer = new EthernetLayer
{
Source = ethernetSource,
Destination = ethernetDestination
};
Random random = new Random();
IpV4Layer ipV4Layer = random.NextIpV4Layer(null);
ipV4Layer.HeaderChecksum = null;
TcpLayer tcpLayer = random.NextTcpLayer();
for (int i = 0; i != 1000; ++i)
{
PayloadLayer payloadLayer = new PayloadLayer
{
Data = new Datagram(Encoding.ASCII.GetBytes("GET /url HTTP/1.1"))
};
Packet packet = new PacketBuilder(ethernetLayer, ipV4Layer, tcpLayer, payloadLayer).Build(DateTime.Now);
Assert.IsTrue(packet.IsValid);
// Ethernet
ethernetLayer.EtherType = EthernetType.IpV4;
Assert.AreEqual(ethernetLayer, packet.Ethernet.ExtractLayer(), "Ethernet Layer");
// IpV4
ipV4Layer.Protocol = IpV4Protocol.Tcp;
ipV4Layer.HeaderChecksum = ((IpV4Layer)packet.Ethernet.IpV4.ExtractLayer()).HeaderChecksum;
Assert.AreEqual(ipV4Layer, packet.Ethernet.IpV4.ExtractLayer(), "IP Layer");
ipV4Layer.HeaderChecksum = null;
// TCP
tcpLayer.Checksum = packet.Ethernet.IpV4.Tcp.Checksum;
Assert.AreEqual(tcpLayer, packet.Ethernet.IpV4.Tcp.ExtractLayer(), "TCP Layer");
// HTTP
HttpDatagram http = packet.Ethernet.IpV4.Tcp.Http;
HttpHeader header = http.Header;
Assert.IsNotNull(header);
}
}
}
}
\ No newline at end of file
......@@ -43,7 +43,7 @@ namespace PcapDotNet.Packets.Test
#endregion
[TestMethod]
public void HttpTest()
public void IpV4HttpTest()
{
Packet packet = HexToPacket(
"feff200001000000010000000800" +
......
......@@ -74,6 +74,7 @@
<Compile Include="EndianitiyTests.cs" />
<Compile Include="EthernetTests.cs" />
<Compile Include="GreTests.cs" />
<Compile Include="HttpTests.cs" />
<Compile Include="IcmpTests.cs" />
<Compile Include="IgmpTests.cs" />
<Compile Include="IpV4Tests.cs" />
......
......@@ -14,7 +14,13 @@ namespace PcapDotNet.Packets
{
public static int Compare(this byte[] array, int offset, byte[] other, int otherOffset, int count)
{
throw new NotImplementedException();
for (int i = 0; i != count; ++i)
{
int compare = array[offset + i].CompareTo(other[otherOffset + i]);
if (compare != 0)
return compare;
}
return 0;
}
public static bool SequenceEqual(this byte[] array, int offset, byte[] other, int otherOffset, int count)
......
......@@ -32,5 +32,7 @@
public const byte EqualsSign = (byte)'=';
public const byte LeftCurlyBracket = (byte)'{';
public const byte RightCurlyBracket = (byte)'}';
public const byte Asterisk = (byte)'*';
public const byte Dot = (byte)'.';
}
}
\ No newline at end of file
......@@ -60,6 +60,34 @@ namespace PcapDotNet.Packets.Http
/// extension-method = token
///
/// Request-URI = "*" | absoluteURI | abs_path | authority
/// absoluteURI = scheme ":" ( hier_part | opaque_part )
/// scheme = alpha *( alpha | digit | "+" | "-" | "." )
/// hier_part = ( net_path | abs_path ) [ "?" query ]
/// opaque_part = uric_no_slash *uric
/// net_path = "//" authority [ abs_path ]
/// abs_path = "/" path_segments
/// query = *uric
/// uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
/// uric = reserved | unreserved | escaped
/// authority = server | reg_name
/// path_segments = segment *( "/" segment )
/// unreserved = alphanum | mark
/// escaped = "%" hex hex
/// reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
/// server = [ [ userinfo "@" ] hostport ]
/// reg_name = 1*( unreserved | escaped | "$" | "," | ";" | ":" | "@" | "&" | "=" | "+" )
/// segment = *pchar *( ";" param )
/// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
/// userinfo = *( unreserved | escaped | ";" | ":" | "&" | "=" | "+" | "$" | "," )
/// hostport = host [ ":" port ]
/// pchar = unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | ","
/// param = *pchar
/// host = hostname | IPv4address
/// port = *digit
/// hostname = *( domainlabel "." ) toplabel [ "." ]
/// IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
/// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
/// toplabel = alpha | alpha *( alphanum | "-" ) alphanum
///
/// request-header = Accept
/// | Accept-Charset
......@@ -188,7 +216,7 @@ namespace PcapDotNet.Packets.Http
_header = new HttpHeader(ParseHeader(parser));
}
internal HttpDatagram CreateDatagram(byte[] buffer, int offset, int length)
internal static HttpDatagram CreateDatagram(byte[] buffer, int offset, int length)
{
if (length >= _httpSlash.Length && buffer.SequenceEqual(offset, _httpSlash, 0, _httpSlash.Length))
return new HttpResponseDatagram(buffer, offset, length);
......
......@@ -38,26 +38,44 @@ namespace PcapDotNet.Packets.Http
return this;
}
private HttpParser Single(byte value)
private HttpParser Bytes(byte value)
{
if (!Success)
return this;
if (Range.First() != value)
var range = Range;
if (!range.Any() || range.First() != value)
return Fail();
++_offset;
return this;
}
private HttpParser Bytes(params byte[] values)
{
if (!Success)
return this;
if (!Range.Take(values.Length).SequenceEqual(values))
return Fail();
_offset += values.Length;
return this;
}
public HttpParser Colon()
{
return Single(AsciiBytes.Colon);
return Bytes(AsciiBytes.Colon);
}
public HttpParser Dot()
{
return Bytes(AsciiBytes.Dot);
}
public HttpParser Space()
{
return Single(AsciiBytes.Space);
return Bytes(AsciiBytes.Space);
}
......@@ -142,37 +160,100 @@ namespace PcapDotNet.Packets.Http
private int _offset;
private readonly int _totalLength;
public HttpParser RequestUri()
public HttpParser RequestUri(out string uri)
{
throw new NotImplementedException();
if (!Success)
{
uri = null;
return this;
}
var range = Range;
int numChars = range.TakeWhile(value => value > 32 && value < 127).Count();
uri = Encoding.ASCII.GetString(_buffer, _offset, numChars);
_offset += numChars;
return this;
}
public HttpParser Version()
public HttpParser Version(out HttpVersion version)
{
throw new NotImplementedException();
uint major;
uint minor;
Bytes(_httpSlash).DecimalNumber(out major).Dot().DecimalNumber(out minor);
version = new HttpVersion(major, minor);
return this;
}
public HttpParser CarraigeReturnLineFeed()
{
return Single(AsciiBytes.CarriageReturn).Single(AsciiBytes.LineFeed);
return Bytes(AsciiBytes.CarriageReturn, AsciiBytes.LineFeed);
}
public HttpParser DecimalNumber(int numDigits, out int number)
public HttpParser DecimalNumber(int numDigits, out uint number)
{
if (!Success)
{
number = 0;
return this;
}
var digits = Range.Take(numDigits).TakeWhile(value => value.IsDigit());
if (digits.Count() != numDigits)
{
number = 0;
return Fail();
}
number = digits.Select(value => value - AsciiBytes.Zero).Aggregate(0, (accumulated, value) => 10 * accumulated + value);
number = digits.Select(value => (uint)(value - AsciiBytes.Zero)).Aggregate<uint, uint>(0, (accumulated, value) => 10 * accumulated + value);
_offset += numDigits;
return this;
}
public HttpParser DecimalNumber(out uint number)
{
if (!Success)
{
number = 0;
return this;
}
var digits = Range.TakeWhile(value => value.IsDigit());
if (!digits.Any())
{
number = 0;
return Fail();
}
int numDigits = digits.Count();
number = digits.Select(value => (uint)(value - AsciiBytes.Zero)).Aggregate<uint, uint>(0, (accumulated, value) => 10 * accumulated + value);
_offset += numDigits;
return this;
}
public HttpParser ReasonPhrase()
public HttpParser ReasonPhrase(out IEnumerable<byte> reasonPhrase)
{
throw new NotImplementedException();
if (!Success)
{
reasonPhrase = null;
return this;
}
reasonPhrase = Range.TakeWhile(value => !value.IsControl() || value == AsciiBytes.HorizontalTab);
_offset += reasonPhrase.Count();
return this;
}
private static readonly byte[] _httpSlash = Encoding.ASCII.GetBytes("HTTP/");
}
public class HttpVersion
{
public HttpVersion(uint major, uint minor)
{
Major = major;
Minor = minor;
}
public uint Major { get; private set; }
public uint Minor { get; private set; }
}
}
\ No newline at end of file
......@@ -17,7 +17,9 @@ namespace PcapDotNet.Packets.Http
internal override void ParseFirstLine(HttpParser parser)
{
string method;
parser.Token(out method).Space().RequestUri().Space().Version().CarraigeReturnLineFeed();
string uri;
HttpVersion version;
parser.Token(out method).Space().RequestUri(out uri).Space().Version(out version).CarraigeReturnLineFeed();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
namespace PcapDotNet.Packets.Http
{
......@@ -16,8 +17,10 @@ namespace PcapDotNet.Packets.Http
internal override void ParseFirstLine(HttpParser parser)
{
int statusCode;
parser.Version().Space().DecimalNumber(3, out statusCode).Space().ReasonPhrase().CarraigeReturnLineFeed();
uint statusCode;
HttpVersion version;
IEnumerable<byte> reasonPhrase;
parser.Version(out version).Space().DecimalNumber(3, out statusCode).Space().ReasonPhrase(out reasonPhrase).CarraigeReturnLineFeed();
}
}
}
\ No newline at end of file
......@@ -234,7 +234,7 @@ namespace PcapDotNet.Packets.IpV4
{
get
{
if (_icmp == null && Length >= HeaderLength)
if (_icmp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_icmp = IcmpDatagram.CreateDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _icmp;
......@@ -248,7 +248,7 @@ namespace PcapDotNet.Packets.IpV4
{
get
{
if (_igmp == null && Length >= HeaderLength)
if (_igmp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_igmp = new IgmpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _igmp;
......@@ -262,7 +262,7 @@ namespace PcapDotNet.Packets.IpV4
{
get
{
if (_tcp == null && Length >= HeaderLength)
if (_tcp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_tcp = new TcpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _tcp;
......@@ -276,7 +276,7 @@ namespace PcapDotNet.Packets.IpV4
{
get
{
if (_gre == null && Length >= HeaderLength)
if (_gre == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_gre = new GreDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _gre;
......@@ -290,7 +290,7 @@ namespace PcapDotNet.Packets.IpV4
{
get
{
if (_udp == null && Length >= HeaderLength)
if (_udp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_udp = new UdpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _udp;
......
using System;
using PcapDotNet.Packets.Http;
namespace PcapDotNet.Packets.Transport
{
......@@ -253,12 +254,28 @@ namespace PcapDotNet.Packets.Transport
};
}
public HttpDatagram Http
{
get
{
if (_http == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_http = HttpDatagram.CreateDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _http;
}
}
/// <summary>
/// The payload of the TCP datagram.
/// </summary>
public Datagram Payload
{
get { return new Datagram(Buffer, StartOffset + HeaderLength, PayloadLength); }
get
{
if (Length < HeaderMinimumLength || Length < HeaderLength)
return null;
return new Datagram(Buffer, StartOffset + HeaderLength, PayloadLength);
}
}
/// <summary>
......@@ -297,5 +314,6 @@ namespace PcapDotNet.Packets.Transport
}
private TcpOptions _options;
private HttpDatagram _http;
}
}
\ No newline at end of file
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