Commit 3ce1f87b authored by Brickner_cp's avatar Brickner_cp

HTTP

parent cc0fd15f
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace PcapDotNet.Base namespace PcapDotNet.Base
...@@ -18,7 +19,26 @@ namespace PcapDotNet.Base ...@@ -18,7 +19,26 @@ namespace PcapDotNet.Base
if (!dictionary2.TryGetValue(pair.Key, out otherValue)) if (!dictionary2.TryGetValue(pair.Key, out otherValue))
return false; return false;
if (!valueComparer.Equals(pair.Value, otherValue)) if (!valueComparer.Equals(pair.Value, otherValue))
{
if (otherValue is string)
{
string otherString = otherValue as string;
string thisString = pair.Value as string;
for (int i = 0; i != otherString.Length; ++i)
{
if (!thisString[i].Equals(otherString[i]))
{
Console.WriteLine("a");
}
else
{
Console.WriteLine("b");
}
}
}
return false; return false;
}
} }
return true; return true;
......
...@@ -98,6 +98,7 @@ ...@@ -98,6 +98,7 @@
<Compile Include="UInt24.cs" /> <Compile Include="UInt24.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UInt48.cs" /> <Compile Include="UInt48.cs" />
<Compile Include="UIntExtensions.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="..\PcapDotNet.snk" /> <None Include="..\PcapDotNet.snk" />
......
using System;
namespace PcapDotNet.Base
{
public static class UIntExtensions
{
public static int NumDigits(this uint value, double digitsBase)
{
return (int)(Math.Floor(Math.Log(value, digitsBase)) + 1);
}
}
}
\ No newline at end of file
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base; using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet; using PcapDotNet.Packets.Ethernet;
...@@ -46,6 +47,44 @@ namespace PcapDotNet.Packets.Test ...@@ -46,6 +47,44 @@ namespace PcapDotNet.Packets.Test
// //
#endregion #endregion
[TestMethod]
public void RandomHttpTest()
{
Random random = new Random(1);
for (int i = 0; i != 1000; ++i)
{
EthernetLayer ethernetLayer = random.NextEthernetLayer(EthernetType.None);
IpV4Layer ipV4Layer = random.NextIpV4Layer(null);
ipV4Layer.HeaderChecksum = null;
TcpLayer tcpLayer = random.NextTcpLayer();
tcpLayer.Checksum = null;
HttpLayer httpLayer = random.NextHttpLayer();
Packet packet = new PacketBuilder(ethernetLayer, ipV4Layer, tcpLayer, httpLayer).Build(DateTime.Now);
Assert.IsTrue(packet.IsValid, "IsValid");
HttpDatagram httpDatagram = packet.Ethernet.IpV4.Tcp.Http;
Assert.AreEqual(httpLayer.Version, httpDatagram.Version);
if (httpLayer is HttpRequestLayer)
{
Assert.IsTrue(httpDatagram.IsRequest);
Assert.IsFalse(httpDatagram.IsResponse);
HttpRequestLayer httpRequestLayer = (HttpRequestLayer)httpLayer;
HttpRequestDatagram httpRequestDatagram = (HttpRequestDatagram)httpDatagram;
Assert.AreEqual(httpRequestLayer.Method, httpRequestDatagram.Method);
Assert.AreEqual(httpRequestLayer.Uri, httpRequestDatagram.Uri);
}
Assert.AreEqual(httpLayer.Header, httpDatagram.Header);
Assert.AreEqual(httpLayer.Body, httpDatagram.Body);
Assert.AreEqual(httpLayer, httpDatagram.ExtractLayer(), "HTTP Layer");
Assert.AreEqual(httpLayer.Length, httpDatagram.Length);
// Ethernet
}
}
[TestMethod] [TestMethod]
public void HttpParsingTest() public void HttpParsingTest()
{ {
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Text;
using PcapDotNet.Base; using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet; using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.IpV4; using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets namespace PcapDotNet.Packets
...@@ -551,6 +553,11 @@ namespace PcapDotNet.Packets ...@@ -551,6 +553,11 @@ namespace PcapDotNet.Packets
offset += UInt48.SizeOf; offset += UInt48.SizeOf;
} }
public static void Write(this byte[] buffer, ref int offset, string value, Encoding encoding)
{
buffer.Write(ref offset, encoding.GetBytes(value));
}
/// <summary> /// <summary>
/// Writes the given value to the buffer. /// Writes the given value to the buffer.
/// </summary> /// </summary>
...@@ -652,6 +659,23 @@ namespace PcapDotNet.Packets ...@@ -652,6 +659,23 @@ namespace PcapDotNet.Packets
buffer.Write(ref offset, value.MillisecondsSinceMidnightUniversalTime, endianity); buffer.Write(ref offset, value.MillisecondsSinceMidnightUniversalTime, endianity);
} }
public static void WriteCarriageReturnLineFeed(this byte[] buffer, int offset)
{
buffer.Write(ref offset, AsciiBytes.CarriageReturn);
buffer.Write(offset, AsciiBytes.LineFeed);
}
public static void WriteCarriageReturnLineFeed(this byte[] buffer, ref int offset)
{
buffer.Write(ref offset, AsciiBytes.CarriageReturn);
buffer.Write(ref offset, AsciiBytes.LineFeed);
}
public static void WriteDecimal(this byte[] buffer, ref int offset, uint value)
{
buffer.Write(ref offset, value.ToString(), Encoding.ASCII);
}
private static bool IsWrongEndianity(Endianity endianity) private static bool IsWrongEndianity(Endianity endianity)
{ {
return (BitConverter.IsLittleEndian == (endianity == Endianity.Big)); return (BitConverter.IsLittleEndian == (endianity == Endianity.Big));
......
...@@ -42,7 +42,14 @@ namespace PcapDotNet.Packets.Http ...@@ -42,7 +42,14 @@ namespace PcapDotNet.Packets.Http
string fieldValueString = HttpRegex.GetString(fieldValue); string fieldValueString = HttpRegex.GetString(fieldValue);
Match match = _regex.Match(fieldValueString); Match match = _regex.Match(fieldValueString);
if (!match.Success) if (!match.Success)
{
while (!match.Success && fieldValueString.Length > 0)
{
fieldValueString = fieldValueString.Substring(0, fieldValueString.Length - 1);
match = _regex.Match(fieldValueString);
}
return; return;
}
MediaType = match.Groups[MediaTypeGroupName].Captures.Cast<Capture>().First().Value; MediaType = match.Groups[MediaTypeGroupName].Captures.Cast<Capture>().First().Value;
MediaSubType = match.Groups[MediaSubTypeGroupName].Captures.Cast<Capture>().First().Value; MediaSubType = match.Groups[MediaSubTypeGroupName].Captures.Cast<Capture>().First().Value;
...@@ -51,7 +58,7 @@ namespace PcapDotNet.Packets.Http ...@@ -51,7 +58,7 @@ namespace PcapDotNet.Packets.Http
} }
private const string MediaTypeGroupName = "MediaType"; private const string MediaTypeGroupName = "MediaType";
private const string MediaSubTypeGroupName = "MediaSubtType"; private const string MediaSubTypeGroupName = "MediaSubType";
private static readonly Regex _regex = private static readonly Regex _regex =
HttpRegex.MatchEntire(HttpRegex.Concat(HttpRegex.Capture(HttpRegex.Token, MediaTypeGroupName), HttpRegex.MatchEntire(HttpRegex.Concat(HttpRegex.Capture(HttpRegex.Token, MediaTypeGroupName),
......
...@@ -198,6 +198,9 @@ namespace PcapDotNet.Packets.Http ...@@ -198,6 +198,9 @@ namespace PcapDotNet.Packets.Http
/// </summary> /// </summary>
public abstract class HttpDatagram : Datagram public abstract class HttpDatagram : Datagram
{ {
private const string FieldNameGroupName = "FieldNameGroupName";
private const string FieldValueGroupName = "FieldValueGroupName";
internal class ParseInfoBase internal class ParseInfoBase
{ {
public int Length { get; set; } public int Length { get; set; }
...@@ -238,10 +241,11 @@ namespace PcapDotNet.Packets.Http ...@@ -238,10 +241,11 @@ namespace PcapDotNet.Packets.Http
return Empty; return Empty;
HttpTransferEncodingField transferEncodingField = header.TransferEncoding; HttpTransferEncodingField transferEncodingField = header.TransferEncoding;
if (transferEncodingField != null) if (transferEncodingField != null &&
transferEncodingField.TransferCodings != null &&
transferEncodingField.TransferCodings.Any(coding => coding != "identity"))
{ {
if (transferEncodingField.TransferCodings.Any(coding => coding != "identity")) return ParseChunkedBody(buffer, offset, length);
return ParseChunkedBody(buffer, offset, length);
} }
HttpContentLengthField contentLengthField = header.ContentLength; HttpContentLengthField contentLengthField = header.ContentLength;
...@@ -284,12 +288,13 @@ namespace PcapDotNet.Packets.Http ...@@ -284,12 +288,13 @@ namespace PcapDotNet.Packets.Http
if (chunkSizeValue == 0) if (chunkSizeValue == 0)
{ {
int? endOffset; int? endOffset;
HttpHeader trailerHeader = new HttpHeader(GetHeaderFields(out endOffset, buffer, parser.Offset, buffer.Length - parser.Offset)); HttpHeader trailerHeader = new HttpHeader(GetHeaderFields(out endOffset, buffer, parser.Offset, offset + length - parser.Offset));
parser.CarriageReturnLineFeed(); if (endOffset != null)
parser.Skip(endOffset.Value - parser.Offset);
break; break;
} }
int actualChunkSize = (int)Math.Min(chunkSizeValue, buffer.Length - parser.Offset); int actualChunkSize = (int)Math.Min(chunkSizeValue, offset + length - parser.Offset);
contentData.Add(new Datagram(buffer, parser.Offset, actualChunkSize)); contentData.Add(new Datagram(buffer, parser.Offset, actualChunkSize));
parser.Skip(actualChunkSize); parser.Skip(actualChunkSize);
parser.CarriageReturnLineFeed(); parser.CarriageReturnLineFeed();
...@@ -330,51 +335,5 @@ namespace PcapDotNet.Packets.Http ...@@ -330,51 +335,5 @@ namespace PcapDotNet.Packets.Http
} }
private static readonly byte[] _httpSlash = Encoding.ASCII.GetBytes("HTTP/"); private static readonly byte[] _httpSlash = Encoding.ASCII.GetBytes("HTTP/");
private bool _isParsedFirstLine;
private bool _isParsedHeader;
private int? _headerOffset;
private int? _bodyOffset;
private HttpVersion _version;
private HttpHeader _header;
private Datagram _body;
} }
// internal static class IEnumerableExtensions
// {
// public static int CountLinearWhiteSpaces(this IEnumerable<byte> sequence)
// {
// int count = 0;
// while (true)
// {
// byte first = sequence.FirstOrDefault();
// if (first == AsciiBytes.CarriageReturn) // CR
// {
// IEnumerable<byte> skippedSequence = sequence.Skip(1);
// if (skippedSequence.FirstOrDefault() == AsciiBytes.LineFeed) // CRLF
// {
// skippedSequence = skippedSequence.Skip(1);
// if (skippedSequence.FirstOrDefault().IsSpaceOrHorizontalTab()) // CRLF ( SP | HT )
// {
// sequence = skippedSequence.Skip(1);
// count += 3;
// }
// else // CRLF without ( SP | HT )
// return count;
// }
// else // CR without LF
// return count;
// }
// else if (first.IsSpaceOrHorizontalTab()) // ( SP | HT )
// {
// ++count;
// sequence = sequence.Skip(1);
// }
// else // Doesn't start with ( CR | SP | HT )
// return count;
// }
// }
// }
} }
\ No newline at end of file
...@@ -31,10 +31,46 @@ namespace PcapDotNet.Packets.Http ...@@ -31,10 +31,46 @@ namespace PcapDotNet.Packets.Http
} }
public HttpField(string name, string value, Encoding encoding) public HttpField(string name, string value, Encoding encoding)
: this(name, encoding.GetBytes(value)) : this(name, encoding.GetBytes(NormalizeValue(value)))
{ {
} }
private static string NormalizeValue(string value)
{
StringBuilder stringBuilder = new StringBuilder(value.Length);
int offset = 0;
while (offset != value.Length)
{
if (value[offset] == '"')
{
int start = offset;
++offset;
while (offset != value.Length && value[offset] != '"')
{
if (value[offset] == '\\' && offset != value.Length - 1)
++offset;
++offset;
}
if (value[offset] == '"')
++offset;
stringBuilder.Append(value.Substring(start, offset - start));
}
else if (value[offset] == '\t' || value[offset] == ' ' || value[offset] == '\r' || value[offset] == '\n')
{
stringBuilder.Append(' ');
++offset;
while (offset != value.Length && (value[offset] == '\t' || value[offset] == ' ' || value[offset] == '\r' || value[offset] == '\n'))
++offset;
}
else
{
stringBuilder.Append(value[offset]);
++offset;
}
}
return stringBuilder.ToString();
}
public HttpField(string name, IEnumerable<byte> value) public HttpField(string name, IEnumerable<byte> value)
: this(name, value.ToArray()) : this(name, value.ToArray())
{ {
...@@ -81,6 +117,14 @@ namespace PcapDotNet.Packets.Http ...@@ -81,6 +117,14 @@ namespace PcapDotNet.Packets.Http
} }
} }
public int Length
{
get
{
return Name.Length + 2 + Value.Count + 2;
}
}
public virtual bool Equals(HttpField other) public virtual bool Equals(HttpField other)
{ {
return other != null && Name.Equals(other.Name, StringComparison.InvariantCultureIgnoreCase) && Value.SequenceEqual(other.Value); return other != null && Name.Equals(other.Name, StringComparison.InvariantCultureIgnoreCase) && Value.SequenceEqual(other.Value);
...@@ -96,6 +140,15 @@ namespace PcapDotNet.Packets.Http ...@@ -96,6 +140,15 @@ namespace PcapDotNet.Packets.Http
return string.Format("{0}: {1}", Name, ValueString); return string.Format("{0}: {1}", Name, ValueString);
} }
internal void Write(byte[] buffer, ref int offset)
{
buffer.Write(ref offset, Name, Encoding.ASCII);
buffer.Write(ref offset, AsciiBytes.Colon);
buffer.Write(ref offset, AsciiBytes.Space);
buffer.Write(ref offset, Value);
buffer.WriteCarriageReturnLineFeed(ref offset);
}
private static readonly Encoding _defaultEncoding = Encoding.GetEncoding(28591); private static readonly Encoding _defaultEncoding = Encoding.GetEncoding(28591);
} }
} }
\ No newline at end of file
...@@ -71,7 +71,7 @@ namespace PcapDotNet.Packets.Http ...@@ -71,7 +71,7 @@ namespace PcapDotNet.Packets.Http
return string.Empty; return string.Empty;
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append(" "); // stringBuilder.Append(" ");
foreach (var parameter in this) foreach (var parameter in this)
{ {
stringBuilder.Append(";"); stringBuilder.Append(";");
......
...@@ -20,6 +20,14 @@ namespace PcapDotNet.Packets.Http ...@@ -20,6 +20,14 @@ namespace PcapDotNet.Packets.Http
{ {
} }
public int BytesLength
{
get
{
return this.Sum(field => field.Length) + 2;
}
}
public HttpField this[string fieldName] public HttpField this[string fieldName]
{ {
get { return GetField<HttpField>(fieldName); } get { return GetField<HttpField>(fieldName); }
...@@ -94,6 +102,18 @@ namespace PcapDotNet.Packets.Http ...@@ -94,6 +102,18 @@ 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);
} }
public void Write(byte[] buffer, int offset)
{
Write(buffer, ref offset);
}
public void Write(byte[] buffer, ref int offset)
{
foreach (HttpField field in this)
field.Write(buffer, ref offset);
buffer.WriteCarriageReturnLineFeed(ref offset);
}
private T GetField<T>(string fieldName) where T : HttpField private T GetField<T>(string fieldName) where T : HttpField
{ {
HttpField field; HttpField field;
......
using System;
namespace PcapDotNet.Packets.Http
{
public abstract class HttpLayer : SimpleLayer, IEquatable<HttpLayer>
{
public HttpVersion Version { get; set; }
public HttpHeader Header { get; set; }
public Datagram Body { get; set; }
public override int Length
{
get
{
return FirstLineLength +
(Header == null ? 0 : Header.BytesLength) +
(Body == null ? 0 : Body.Length);
}
}
public override bool Equals(Layer other)
{
return Equals(other as HttpLayer);
}
public virtual bool Equals(HttpLayer other)
{
return other != null &&
(ReferenceEquals(Version, other.Version) || Version.Equals(other.Version)) &&
(ReferenceEquals(Header, other.Header) || Header.Equals(other.Header)) &&
(ReferenceEquals(Body, other.Body) || Body.Equals(other.Body));
}
protected override void Write(byte[] buffer, int offset)
{
WriteFirstLine(buffer, ref offset);
if (Header != null)
Header.Write(buffer, ref offset);
if (Body != null)
buffer.Write(offset, Body);
}
protected abstract int FirstLineLength { get; }
protected abstract void WriteFirstLine(byte[] buffer, ref int offset);
}
}
\ No newline at end of file
...@@ -103,8 +103,29 @@ namespace PcapDotNet.Packets.Http ...@@ -103,8 +103,29 @@ namespace PcapDotNet.Packets.Http
public HttpParser FieldContent(out IEnumerable<byte> fieldContent) public HttpParser FieldContent(out IEnumerable<byte> fieldContent)
{ {
fieldContent = Range.TakeWhile(value => !value.IsSpaceOrHorizontalTab() && value != AsciiBytes.CarriageReturn); int originalOffset = Offset;
_offset += fieldContent.Count(); fieldContent = null;
while (Success)
{
fieldContent = new Datagram(_buffer, originalOffset, Offset - originalOffset);
if (IsNext(AsciiBytes.Space) || IsNext(AsciiBytes.CarriageReturn) || IsNext(AsciiBytes.HorizontalTab) || IsNext(AsciiBytes.LineFeed))
break;
if (IsNext(AsciiBytes.DoubleQuotationMark))
{
Datagram quotedString;
QuotedString(out quotedString);
}
else
{
var text = Range.TakeWhile(value => value > 0x20 && value != AsciiBytes.DoubleQuotationMark);
if (!text.Any())
return Fail();
_offset += text.Count();
}
}
return this; return this;
} }
...@@ -319,7 +340,7 @@ namespace PcapDotNet.Packets.Http ...@@ -319,7 +340,7 @@ namespace PcapDotNet.Packets.Http
public HttpParser SkipChunkExtensions() public HttpParser SkipChunkExtensions()
{ {
while (IsNext(AsciiBytes.Semicolon)) while (Success && IsNext(AsciiBytes.Semicolon))
{ {
Bytes(AsciiBytes.Semicolon); Bytes(AsciiBytes.Semicolon);
......
...@@ -9,6 +9,11 @@ namespace PcapDotNet.Packets.Http ...@@ -9,6 +9,11 @@ namespace PcapDotNet.Packets.Http
public const string ParameterNameGroupName = "ParameterName"; public const string ParameterNameGroupName = "ParameterName";
public const string ParameterValueGroupName = "ParameterValue"; public const string ParameterValueGroupName = "ParameterValue";
public static Regex CarriageReturnLineFeed
{
get { return _carriageReturnLineFeed; }
}
public static Regex LinearWhiteSpace public static Regex LinearWhiteSpace
{ {
get { return _linearWhiteSpaceRegex; } get { return _linearWhiteSpaceRegex; }
...@@ -29,9 +34,19 @@ namespace PcapDotNet.Packets.Http ...@@ -29,9 +34,19 @@ namespace PcapDotNet.Packets.Http
get { return _optionalParametersRegex; } get { return _optionalParametersRegex; }
} }
public static string GetString(byte[] buffer, int offset, int count)
{
return _encoding.GetString(buffer, offset, count);
}
public static string GetString(byte[] buffer) public static string GetString(byte[] buffer)
{ {
return _encoding.GetString(buffer); return GetString(buffer, 0, buffer.Length);
}
public static byte[] GetBytes(string pattern)
{
return _encoding.GetBytes(pattern);
} }
public static Regex Build(string pattern) public static Regex Build(string pattern)
...@@ -91,6 +106,11 @@ namespace PcapDotNet.Packets.Http ...@@ -91,6 +106,11 @@ namespace PcapDotNet.Packets.Http
return Build(string.Format("(?<{0}>{1})", captureName, regex)); return Build(string.Format("(?<{0}>{1})", captureName, regex));
} }
public static Regex MatchStart(Regex regex)
{
return Build(string.Format("^{0}", regex));
}
public static Regex MatchEntire(Regex regex) public static Regex MatchEntire(Regex regex)
{ {
return Build(string.Format("^{0}$", regex)); return Build(string.Format("^{0}$", regex));
...@@ -101,10 +121,11 @@ namespace PcapDotNet.Packets.Http ...@@ -101,10 +121,11 @@ namespace PcapDotNet.Packets.Http
return string.Format("(?:{0})", pattern); return string.Format("(?:{0})", pattern);
} }
private static readonly Regex _charRegex = Build(@"[\x00-\x127]"); private static readonly Regex _carriageReturnLineFeed = Build(@"\r\n");
private static readonly Regex _charRegex = Build(@"[\x00-\x7F]");
private static readonly Regex _quotedPairRegex = Concat(Build(@"\\"), _charRegex); private static readonly Regex _quotedPairRegex = Concat(Build(@"\\"), _charRegex);
private static readonly Regex _linearWhiteSpaceRegex = Concat(Optional(Build(@"\r\n")), AtLeastOne(Build(@"[ \t]"))); private static readonly Regex _linearWhiteSpaceRegex = Concat(Optional(CarriageReturnLineFeed), AtLeastOne(Build(@"[ \t]")));
private static readonly Regex _qdtextRegex = Or(_linearWhiteSpaceRegex, Build(@"[^\x00-\x31\x127\""]")); private static readonly Regex _qdtextRegex = Or(_linearWhiteSpaceRegex, Build(@"[^\x00-\x1F\x7F""]"));
private static readonly Regex _quotedStringRegex = Concat(Build('"'), Any(Or(_qdtextRegex, _quotedPairRegex)), Build('"')); private static readonly Regex _quotedStringRegex = Concat(Build('"'), Any(Or(_qdtextRegex, _quotedPairRegex)), Build('"'));
private static readonly Regex _tokenRegex = AtLeastOne(Build(@"[\x21\x23-\x27\x2A\x2B\x2D\x2E0-9A-Z\x5E-\x7A\x7C\x7E-\xFE]")); private static readonly Regex _tokenRegex = AtLeastOne(Build(@"[\x21\x23-\x27\x2A\x2B\x2D\x2E0-9A-Z\x5E-\x7A\x7C\x7E-\xFE]"));
private static readonly Regex _valueRegex = Or(Token, QuotedString); private static readonly Regex _valueRegex = Or(Token, QuotedString);
......
...@@ -18,6 +18,18 @@ namespace PcapDotNet.Packets.Http ...@@ -18,6 +18,18 @@ namespace PcapDotNet.Packets.Http
public string Method { get; private set; } public string Method { get; private set; }
public string Uri { get; private set; } public string Uri { get; private set; }
public override ILayer ExtractLayer()
{
return new HttpRequestLayer
{
Version = Version,
Method = Method,
Uri = Uri,
Header = Header,
Body = Body,
};
}
internal HttpRequestDatagram(byte[] buffer, int offset, int length) internal HttpRequestDatagram(byte[] buffer, int offset, int length)
: this(buffer, offset, Parse(buffer, offset, length)) : this(buffer, offset, Parse(buffer, offset, length))
{ {
......
using System;
using System.Text;
namespace PcapDotNet.Packets.Http
{
public class HttpRequestLayer : HttpLayer, IEquatable<HttpRequestLayer>
{
public string Method { get; set; }
public string Uri { get; set; }
public override bool Equals(HttpLayer other)
{
return Equals(other as HttpRequestLayer);
}
public bool Equals(HttpRequestLayer other)
{
return base.Equals(other) &&
(ReferenceEquals(Method, other.Method) || Method.Equals(other.Method)) &&
(ReferenceEquals(Uri, other.Uri) || Uri.Equals(other.Uri));
}
protected override int FirstLineLength
{
get
{
int length = 0;
if (Method == null)
return length;
length += Method.Length + 1;
if (Uri == null)
return length;
length += Uri.Length + 1;
if (Version == null)
return length;
return length + Version.Length + 2;
}
}
protected override void WriteFirstLine(byte[] buffer, ref int offset)
{
if (Method == null)
return;
buffer.Write(ref offset, Method, Encoding.ASCII);
buffer.Write(ref offset, AsciiBytes.Space);
if (Uri == null)
return;
buffer.Write(ref offset, Uri, Encoding.ASCII);
buffer.Write(ref offset, AsciiBytes.Space);
if (Version == null)
return;
Version.Write(buffer, ref offset);
buffer.WriteCarriageReturnLineFeed(ref offset);
}
}
}
\ No newline at end of file
...@@ -20,6 +20,18 @@ namespace PcapDotNet.Packets.Http ...@@ -20,6 +20,18 @@ namespace PcapDotNet.Packets.Http
public Datagram ReasonPhrase { get; private set;} public Datagram ReasonPhrase { get; private set;}
public override ILayer ExtractLayer()
{
return new HttpResponseLayer
{
Version = Version,
StatusCode = StatusCode,
ReasonPhrase = ReasonPhrase,
Header = Header,
Body = Body,
};
}
internal HttpResponseDatagram(byte[] buffer, int offset, int length) internal HttpResponseDatagram(byte[] buffer, int offset, int length)
: this(buffer, offset, Parse(buffer, offset, length)) : this(buffer, offset, Parse(buffer, offset, length))
{ {
......
using System;
using PcapDotNet.Base;
namespace PcapDotNet.Packets.Http
{
public class HttpResponseLayer : HttpLayer, IEquatable<HttpResponseLayer>
{
public uint? StatusCode { get; set; }
public Datagram ReasonPhrase { get; set; }
public override bool Equals(HttpLayer other)
{
return Equals(other as HttpResponseLayer);
}
public bool Equals(HttpResponseLayer other)
{
return base.Equals(other) &&
StatusCode == other.StatusCode &&
ReasonPhrase == other.ReasonPhrase;
}
protected override int FirstLineLength
{
get
{
int length = 0;
if (Version == null)
return length;
length += Version.Length + 1;
if (StatusCode == null)
return length;
length += StatusCode.Value.NumDigits(10) + 1;
if (ReasonPhrase == null)
return length;
return length + ReasonPhrase.Length + 2;
}
}
protected override void WriteFirstLine(byte[] buffer, ref int offset)
{
if (Version == null)
return;
Version.Write(buffer, ref offset);
buffer.Write(ref offset, AsciiBytes.Space);
if (StatusCode == null)
return;
buffer.WriteDecimal(ref offset, StatusCode.Value);
buffer.Write(ref offset, AsciiBytes.Space);
if (ReasonPhrase == null)
return;
buffer.Write(ref offset, ReasonPhrase);
buffer.WriteCarriageReturnLineFeed(ref offset);
}
}
}
\ No newline at end of file
...@@ -51,10 +51,22 @@ namespace PcapDotNet.Packets.Http ...@@ -51,10 +51,22 @@ namespace PcapDotNet.Packets.Http
internal HttpTransferEncodingField(byte[] fieldValue) internal HttpTransferEncodingField(byte[] fieldValue)
: base(Name, fieldValue) : base(Name, fieldValue)
{ {
// string str = "\"h2ÇõX{âDv¼¯Ñ•)ËX?´ÈÔ\"";
// string str = "\"h2ÇõX{âDv¼¯Ñ)\"";
// Match tmpMatch = HttpRegex.QuotedString.Match(str);
// Console.WriteLine(tmpMatch.Success);
string fieldValueString = HttpRegex.GetString(fieldValue); string fieldValueString = HttpRegex.GetString(fieldValue);
Match match = _regex.Match(fieldValueString); Match match = _regex.Match(fieldValueString);
if (!match.Success) if (!match.Success)
{
while (!match.Success && fieldValueString.Length > 0)
{
fieldValueString = fieldValueString.Substring(0, fieldValueString.Length - 1);
match = _regex.Match(fieldValueString);
}
return; return;
}
SetTransferCodings(match.GroupCapturesValues(RegexTransferCodingGroupName).ToArray()); SetTransferCodings(match.GroupCapturesValues(RegexTransferCodingGroupName).ToArray());
} }
......
using System; using System;
using System.Text;
using PcapDotNet.Base;
namespace PcapDotNet.Packets.Http namespace PcapDotNet.Packets.Http
{ {
...@@ -16,6 +18,11 @@ namespace PcapDotNet.Packets.Http ...@@ -16,6 +18,11 @@ namespace PcapDotNet.Packets.Http
public uint Major { get; private set; } public uint Major { get; private set; }
public uint Minor { get; private set; } public uint Minor { get; private set; }
public int Length
{
get { return _httpSlashBytes.Length + Major.NumDigits(10) + 1 + Minor.NumDigits(10); }
}
public override string ToString() public override string ToString()
{ {
return string.Format("HTTP/{0}.{1}", Major, Minor); return string.Format("HTTP/{0}.{1}", Major, Minor);
...@@ -33,7 +40,16 @@ namespace PcapDotNet.Packets.Http ...@@ -33,7 +40,16 @@ namespace PcapDotNet.Packets.Http
return Equals(obj as HttpVersion); return Equals(obj as HttpVersion);
} }
internal void Write(byte[] buffer, ref int offset)
{
buffer.Write(ref offset, _httpSlashBytes);
buffer.WriteDecimal(ref offset, Major);
buffer.Write(ref offset, AsciiBytes.Dot);
buffer.WriteDecimal(ref offset, Minor);
}
private static readonly HttpVersion _version10 = new HttpVersion(1,0); private static readonly HttpVersion _version10 = new HttpVersion(1,0);
private static readonly HttpVersion _version11 = new HttpVersion(1,1); private static readonly HttpVersion _version11 = new HttpVersion(1,1);
private static readonly byte[] _httpSlashBytes = Encoding.ASCII.GetBytes("HTTP/");
} }
} }
\ No newline at end of file
...@@ -117,10 +117,13 @@ ...@@ -117,10 +117,13 @@
<Compile Include="Http\HttpField.cs" /> <Compile Include="Http\HttpField.cs" />
<Compile Include="Http\HttpFieldParameters.cs" /> <Compile Include="Http\HttpFieldParameters.cs" />
<Compile Include="Http\HttpHeader.cs" /> <Compile Include="Http\HttpHeader.cs" />
<Compile Include="Http\HttpLayer.cs" />
<Compile Include="Http\HttpParser.cs" /> <Compile Include="Http\HttpParser.cs" />
<Compile Include="Http\HttpRegex.cs" /> <Compile Include="Http\HttpRegex.cs" />
<Compile Include="Http\HttpRequestDatagram.cs" /> <Compile Include="Http\HttpRequestDatagram.cs" />
<Compile Include="Http\HttpRequestLayer.cs" />
<Compile Include="Http\HttpResponseDatagram.cs" /> <Compile Include="Http\HttpResponseDatagram.cs" />
<Compile Include="Http\HttpResponseLayer.cs" />
<Compile Include="Http\HttpTransferEncodingField.cs" /> <Compile Include="Http\HttpTransferEncodingField.cs" />
<Compile Include="Http\HttpVersion.cs" /> <Compile Include="Http\HttpVersion.cs" />
<Compile Include="Icmp\IcmpAddressMaskReplyDatagram.cs" /> <Compile Include="Icmp\IcmpAddressMaskReplyDatagram.cs" />
......
...@@ -34,6 +34,11 @@ namespace PcapDotNet.TestUtils ...@@ -34,6 +34,11 @@ namespace PcapDotNet.TestUtils
return bytes; return bytes;
} }
public static char NextChar(this Random random, char minValue, char maxValue)
{
return (char)random.Next(minValue, maxValue);
}
public static ushort NextUShort(this Random random, int maxValue) public static ushort NextUShort(this Random random, int maxValue)
{ {
return (ushort)random.Next(maxValue); return (ushort)random.Next(maxValue);
......
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