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 ...@@ -43,7 +43,7 @@ namespace PcapDotNet.Packets.Test
#endregion #endregion
[TestMethod] [TestMethod]
public void HttpTest() public void IpV4HttpTest()
{ {
Packet packet = HexToPacket( Packet packet = HexToPacket(
"feff200001000000010000000800" + "feff200001000000010000000800" +
......
...@@ -74,6 +74,7 @@ ...@@ -74,6 +74,7 @@
<Compile Include="EndianitiyTests.cs" /> <Compile Include="EndianitiyTests.cs" />
<Compile Include="EthernetTests.cs" /> <Compile Include="EthernetTests.cs" />
<Compile Include="GreTests.cs" /> <Compile Include="GreTests.cs" />
<Compile Include="HttpTests.cs" />
<Compile Include="IcmpTests.cs" /> <Compile Include="IcmpTests.cs" />
<Compile Include="IgmpTests.cs" /> <Compile Include="IgmpTests.cs" />
<Compile Include="IpV4Tests.cs" /> <Compile Include="IpV4Tests.cs" />
......
...@@ -14,7 +14,13 @@ namespace PcapDotNet.Packets ...@@ -14,7 +14,13 @@ namespace PcapDotNet.Packets
{ {
public static int Compare(this byte[] array, int offset, byte[] other, int otherOffset, int count) 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) public static bool SequenceEqual(this byte[] array, int offset, byte[] other, int otherOffset, int count)
......
...@@ -32,5 +32,7 @@ ...@@ -32,5 +32,7 @@
public const byte EqualsSign = (byte)'='; public const byte EqualsSign = (byte)'=';
public const byte LeftCurlyBracket = (byte)'{'; public const byte LeftCurlyBracket = (byte)'{';
public const byte RightCurlyBracket = (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 ...@@ -60,6 +60,34 @@ namespace PcapDotNet.Packets.Http
/// extension-method = token /// extension-method = token
/// ///
/// Request-URI = "*" | absoluteURI | abs_path | authority /// 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 /// request-header = Accept
/// | Accept-Charset /// | Accept-Charset
...@@ -188,7 +216,7 @@ namespace PcapDotNet.Packets.Http ...@@ -188,7 +216,7 @@ namespace PcapDotNet.Packets.Http
_header = new HttpHeader(ParseHeader(parser)); _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)) if (length >= _httpSlash.Length && buffer.SequenceEqual(offset, _httpSlash, 0, _httpSlash.Length))
return new HttpResponseDatagram(buffer, offset, length); return new HttpResponseDatagram(buffer, offset, length);
......
...@@ -38,26 +38,44 @@ namespace PcapDotNet.Packets.Http ...@@ -38,26 +38,44 @@ namespace PcapDotNet.Packets.Http
return this; return this;
} }
private HttpParser Single(byte value) private HttpParser Bytes(byte value)
{ {
if (!Success) if (!Success)
return this; return this;
if (Range.First() != value) var range = Range;
if (!range.Any() || range.First() != value)
return Fail(); return Fail();
++_offset; ++_offset;
return this; 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() public HttpParser Colon()
{ {
return Single(AsciiBytes.Colon); return Bytes(AsciiBytes.Colon);
}
public HttpParser Dot()
{
return Bytes(AsciiBytes.Dot);
} }
public HttpParser Space() public HttpParser Space()
{ {
return Single(AsciiBytes.Space); return Bytes(AsciiBytes.Space);
} }
...@@ -142,37 +160,100 @@ namespace PcapDotNet.Packets.Http ...@@ -142,37 +160,100 @@ namespace PcapDotNet.Packets.Http
private int _offset; private int _offset;
private readonly int _totalLength; private readonly int _totalLength;
public HttpParser RequestUri() public HttpParser RequestUri(out string uri)
{
if (!Success)
{ {
throw new NotImplementedException(); 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() 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()); var digits = Range.Take(numDigits).TakeWhile(value => value.IsDigit());
if (digits.Count() != numDigits) if (digits.Count() != numDigits)
{ {
number = 0; number = 0;
return Fail(); 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; _offset += numDigits;
return this; 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 ...@@ -17,7 +17,9 @@ namespace PcapDotNet.Packets.Http
internal override void ParseFirstLine(HttpParser parser) internal override void ParseFirstLine(HttpParser parser)
{ {
string method; 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;
using System.Collections.Generic;
namespace PcapDotNet.Packets.Http namespace PcapDotNet.Packets.Http
{ {
...@@ -16,8 +17,10 @@ namespace PcapDotNet.Packets.Http ...@@ -16,8 +17,10 @@ namespace PcapDotNet.Packets.Http
internal override void ParseFirstLine(HttpParser parser) internal override void ParseFirstLine(HttpParser parser)
{ {
int statusCode; uint statusCode;
parser.Version().Space().DecimalNumber(3, out statusCode).Space().ReasonPhrase().CarraigeReturnLineFeed(); 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 ...@@ -234,7 +234,7 @@ namespace PcapDotNet.Packets.IpV4
{ {
get get
{ {
if (_icmp == null && Length >= HeaderLength) if (_icmp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_icmp = IcmpDatagram.CreateDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength); _icmp = IcmpDatagram.CreateDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _icmp; return _icmp;
...@@ -248,7 +248,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -248,7 +248,7 @@ namespace PcapDotNet.Packets.IpV4
{ {
get get
{ {
if (_igmp == null && Length >= HeaderLength) if (_igmp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_igmp = new IgmpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength); _igmp = new IgmpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _igmp; return _igmp;
...@@ -262,7 +262,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -262,7 +262,7 @@ namespace PcapDotNet.Packets.IpV4
{ {
get get
{ {
if (_tcp == null && Length >= HeaderLength) if (_tcp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_tcp = new TcpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength); _tcp = new TcpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _tcp; return _tcp;
...@@ -276,7 +276,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -276,7 +276,7 @@ namespace PcapDotNet.Packets.IpV4
{ {
get get
{ {
if (_gre == null && Length >= HeaderLength) if (_gre == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_gre = new GreDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength); _gre = new GreDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _gre; return _gre;
...@@ -290,7 +290,7 @@ namespace PcapDotNet.Packets.IpV4 ...@@ -290,7 +290,7 @@ namespace PcapDotNet.Packets.IpV4
{ {
get get
{ {
if (_udp == null && Length >= HeaderLength) if (_udp == null && Length >= HeaderMinimumLength && Length >= HeaderLength)
_udp = new UdpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength); _udp = new UdpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
return _udp; return _udp;
......
using System; using System;
using PcapDotNet.Packets.Http;
namespace PcapDotNet.Packets.Transport namespace PcapDotNet.Packets.Transport
{ {
...@@ -253,12 +254,28 @@ 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> /// <summary>
/// The payload of the TCP datagram. /// The payload of the TCP datagram.
/// </summary> /// </summary>
public Datagram Payload 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> /// <summary>
...@@ -297,5 +314,6 @@ namespace PcapDotNet.Packets.Transport ...@@ -297,5 +314,6 @@ namespace PcapDotNet.Packets.Transport
} }
private TcpOptions _options; 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