Commit f0e4f8f6 authored by Brickner_cp's avatar Brickner_cp

HTTP

parent 5b45d41c
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
namespace PcapDotNet.Base
{
public static class MatchExtensions
{
public static IEnumerable<string> GroupCapturesValues(this Match match, string groupName)
{
return match.Groups[groupName].Captures.Cast<Capture>().Select(capture => capture.Value);
}
}
}
\ No newline at end of file
......@@ -90,6 +90,7 @@
<Compile Include="IDictionaryExtensions.cs" />
<Compile Include="IEnumerableExtensions.cs" />
<Compile Include="IListExtensions.cs" />
<Compile Include="MatchExtensions.cs" />
<Compile Include="PropertyInfoExtensions.cs" />
<Compile Include="TimeSpanExtensions.cs" />
<Compile Include="TypeExtensions.cs" />
......
......@@ -85,7 +85,7 @@ namespace PcapDotNet.Packets.Test
"\r\n" +
"A: B\r\n",
"GET", "/url", HttpVersion.Version11,
new HttpHeader());
new HttpHeader(), Datagram.Empty);
TestHttpRequest("GET /url HTTP/1.1\r\n" +
"A: B\r\n" +
......@@ -93,7 +93,7 @@ namespace PcapDotNet.Packets.Test
"B: C\r\n",
"GET", "/url", HttpVersion.Version11,
new HttpHeader(
new HttpField("A", "B")));
new HttpField("A", "B")), Datagram.Empty);
TestHttpRequest("GET /url HTTP/1.1\r\n" +
"A: B\r\n" +
......@@ -161,7 +161,7 @@ namespace PcapDotNet.Packets.Test
HttpRequestDatagram request = (HttpRequestDatagram)http;
Assert.AreEqual(expectedMethod, request.Method, "Method " + httpString);
Assert.AreEqual(expectedUri, request.Uri, "Uri " + httpString);
Assert.AreEqual(expectedBody, request.Body);
Assert.AreEqual(expectedBody, request.Body, "Body " + httpString);
}
private static void TestHttpResponse(string httpString, HttpVersion expectedVersion = null, uint? expectedStatusCode = null, string expectedReasonPhrase = null, HttpHeader expectedHeader = null, Datagram expectedBody = null)
......
......@@ -28,6 +28,27 @@ namespace PcapDotNet.Packets
return array.Compare(offset, other, otherOffset, count) == 0;
}
public static int Find(this byte[] array, int offset, int count, byte[] other, int otherOffset, int otherCount)
{
if (otherCount > count)
return array.Length;
int maxOffset = offset + count - otherCount;
while (offset < maxOffset)
{
if (Compare(array, offset, other, otherOffset, otherCount) == 0)
return offset;
++offset;
}
return array.Length;
}
public static int Find(this byte[] array, int offset, int count, byte[] other)
{
return array.Find(offset, count, other, 0, other.Length);
}
/// <summary>
/// Copies a specified number of bytes from a source array starting at a particular offset to a destination array starting at a particular offset.
/// </summary>
......
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text.RegularExpressions;
using PcapDotNet.Base;
namespace PcapDotNet.Packets.Http
{
public class HttpContentTypeField : HttpField, IEquatable<HttpContentTypeField>
{
public const string Name = "Content-Type";
public bool Equals(HttpContentTypeField other)
{
return other != null &&
MediaType == other.MediaType &&
MediaSubType == other.MediaSubType &&
Parameters == other.Parameters;
}
public string MediaType { get; private set; }
public string MediaSubType { get; private set; }
public HttpFieldParameters Parameters { get; private set;}
public override bool Equals(HttpField other)
{
return Equals(other as HttpContentTypeField);
}
internal HttpContentTypeField(byte[] fieldValue)
: base(Name, fieldValue)
{
string fieldValueString = HttpRegex.GetString(fieldValue);
Match match = _regex.Match(fieldValueString);
if (!match.Success)
return;
MediaType = match.Groups[MediaTypeGroupName].Captures.Cast<Capture>().First().Value;
MediaSubType = match.Groups[MediaSubTypeGroupName].Captures.Cast<Capture>().First().Value;
Parameters = new HttpFieldParameters(match.GroupCapturesValues(HttpRegex.ParameterNameGroupName),
match.GroupCapturesValues(HttpRegex.ParameterValueGroupName));
}
private const string MediaTypeGroupName = "MediaType";
private const string MediaSubTypeGroupName = "MediaSubtType";
private static readonly Regex _regex =
HttpRegex.MatchEntire(HttpRegex.Concat(HttpRegex.Capture(HttpRegex.Token, MediaTypeGroupName),
HttpRegex.Build('/'),
HttpRegex.Capture(HttpRegex.Token, MediaSubTypeGroupName),
HttpRegex.OptionalParameters));
}
}
\ No newline at end of file
......@@ -231,7 +231,7 @@ namespace PcapDotNet.Packets.Http
int bodyOffsetValue = _bodyOffset.Value;
if (!IsBodyPossible)
{
_body = new Datagram(new byte[0]);
_body = Empty;
return _body;
}
......@@ -245,24 +245,35 @@ namespace PcapDotNet.Packets.Http
}
}
// HttpContentLengthField contentLengthField = Header.ContentLength;
// if (contentLengthField != null)
// {
// int contentLength = contentLengthField.ContentLength;
// _body = new Datagram(Buffer, StartOffset + bodyOffsetValue, Math.Min(contentLength, Length - bodyOffsetValue));
// return _body;
// }
//
// HttpContentTypeField contentTypeField = Header.ContentType;
// if (contentTypeField != null)
// {
// if (contentTypeField.MediaTypes.Contains("multipart/byteranges"))
// {
// int transferLength = contentTypeField.TransferLength;
// _body = new Datagram(Buffer, StartOffset + bodyOffsetValue, Math.Min(transferLength, Length - bodyOffsetValue));
// }
//
// }
HttpContentLengthField contentLengthField = Header.ContentLength;
if (contentLengthField != null)
{
uint? contentLength = contentLengthField.ContentLength;
if (contentLength != null)
{
_body = new Datagram(Buffer, StartOffset + bodyOffsetValue, Math.Min((int)contentLength.Value, Length - bodyOffsetValue));
return _body;
}
}
HttpContentTypeField contentTypeField = Header.ContentType;
if (contentTypeField != null)
{
if (contentTypeField.MediaType == "multipart" &&
contentTypeField.MediaSubType == "byteranges")
{
string boundary = contentTypeField.Parameters["boundary"];
if (boundary != null)
{
byte[] lastBoundaryBuffer = Encoding.ASCII.GetBytes(string.Format("--{0}--\r\n", boundary));
int lastBoundaryOffset = Buffer.Find(StartOffset + bodyOffsetValue, Length - bodyOffsetValue, lastBoundaryBuffer);
int lastBoundaryEnd = lastBoundaryOffset + lastBoundaryBuffer.Length;
_body = new Datagram(Buffer, StartOffset + bodyOffsetValue,
Math.Min(lastBoundaryEnd - StartOffset - bodyOffsetValue, Length - bodyOffsetValue));
return _body;
}
}
}
_body = new Datagram(Buffer, StartOffset + bodyOffsetValue, Length - bodyOffsetValue);
}
......
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace PcapDotNet.Packets.Http
{
public class HttpFieldParameters : IEnumerable<KeyValuePair<string, string>>
{
internal HttpFieldParameters(IEnumerable<string> parametersNames, IEnumerable<string> parametersValues)
{
var nameEnumerator = parametersNames.GetEnumerator();
var valueEnumerator = parametersValues.GetEnumerator();
while (nameEnumerator.MoveNext())
{
if (!valueEnumerator.MoveNext())
throw new ArgumentException(string.Format("more names ({0}) were given than values ({1})", parametersNames.Count(), parametersValues.Count()), "parametersValues");
_parameters.Add(nameEnumerator.Current, valueEnumerator.Current);
}
if (valueEnumerator.MoveNext())
throw new ArgumentException(string.Format("more values ({0}) were given than names ({1})", parametersValues.Count(), parametersNames.Count()), "parametersNames");
}
public string this[string name]
{
get
{
string value;
if (!_parameters.TryGetValue(name, out value))
return null;
return value;
}
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return _parameters.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private readonly Dictionary<string, string> _parameters = new Dictionary<string, string>();
}
}
\ No newline at end of file
......@@ -22,10 +22,31 @@ namespace PcapDotNet.Packets.Http
{
get
{
HttpField field;
if (!_fields.TryGetValue(HttpTransferEncodingField.Name, out field))
return null;
return (HttpTransferEncodingField)field;
return GetField<HttpTransferEncodingField>(HttpTransferEncodingField.Name);
}
}
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
{
get
{
return GetField<HttpContentLengthField>(HttpContentLengthField.Name);
}
}
public HttpContentTypeField ContentType
{
get
{
return GetField<HttpContentTypeField>(HttpContentTypeField.Name);
}
}
......
......@@ -6,6 +6,9 @@ namespace PcapDotNet.Packets.Http
{
internal static class HttpRegex
{
public const string ParameterNameGroupName = "ParameterName";
public const string ParameterValueGroupName = "ParameterValue";
public static Regex LinearWhiteSpace
{
get { return _linearWhiteSpaceRegex; }
......@@ -21,6 +24,11 @@ namespace PcapDotNet.Packets.Http
get { return _quotedStringRegex; }
}
public static Regex OptionalParameters
{
get { return _optionalParametersRegex; }
}
public static string GetString(byte[] buffer)
{
return _encoding.GetString(buffer);
......@@ -99,6 +107,9 @@ namespace PcapDotNet.Packets.Http
private static readonly Regex _qdtextRegex = Or(_linearWhiteSpaceRegex, Build(@"[^\x00-\x31\x127\""]"));
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 _valueRegex = Or(Token, QuotedString);
private static readonly Regex _parameterRegex = Concat(Capture(_tokenRegex, ParameterNameGroupName), Build("="), Capture(_valueRegex, ParameterValueGroupName));
private static readonly Regex _optionalParametersRegex = Any(Concat(Build(";"), _parameterRegex));
private static readonly Encoding _encoding = Encoding.GetEncoding(28591);
}
......
......@@ -34,7 +34,7 @@ namespace PcapDotNet.Packets.Http
protected override bool IsBodyPossible
{
get { throw new NotImplementedException(); }
get { return Header.ContentLength != null; }
}
internal override void ParseSpecificFirstLine(out HttpVersion version, out int? headerOffset)
......
......@@ -39,7 +39,7 @@ namespace PcapDotNet.Packets.Http
if (transferCodings.Any(coding => coding.Any(c => c.IsUpperCaseAlpha())))
_transferCodings = transferCodings.Select(coding => coding.ToLowerInvariant()).ToArray().AsReadOnly();
else
_transferCodings = _transferCodings.AsReadOnly();
_transferCodings = transferCodings.AsReadOnly();
}
public override bool Equals(HttpField other)
......@@ -55,7 +55,7 @@ namespace PcapDotNet.Packets.Http
if (!match.Success)
return;
SetTransferCodings(match.Groups[RegexTransferCodingGroupName].Captures.Cast<Capture>().Select(capture => capture.Value).ToArray());
SetTransferCodings(match.GroupCapturesValues(RegexTransferCodingGroupName).ToArray());
}
protected override string ValueToString()
......@@ -65,10 +65,7 @@ namespace PcapDotNet.Packets.Http
private ReadOnlyCollection<string> _transferCodings;
private static readonly Regex _valueRegex = HttpRegex.Or(HttpRegex.Token, HttpRegex.QuotedString);
private static readonly Regex _attributeRegex = HttpRegex.Token;
private static readonly Regex _parameterRegex = HttpRegex.Concat(_attributeRegex, HttpRegex.Build("="), _valueRegex);
private static readonly Regex _transferExtensionRegex = HttpRegex.Concat(HttpRegex.Token, HttpRegex.Any(HttpRegex.Concat(HttpRegex.Build(";"), _parameterRegex)));
private static readonly Regex _transferExtensionRegex = HttpRegex.Concat(HttpRegex.Token, HttpRegex.OptionalParameters);
private static readonly Regex _transferCodingRegex = HttpRegex.Capture(HttpRegex.Or(HttpRegex.Build("chunked"), _transferExtensionRegex), RegexTransferCodingGroupName);
private static readonly Regex _regex = HttpRegex.MatchEntire(HttpRegex.CommaSeparatedRegex(_transferCodingRegex, 1));
}
......
......@@ -112,8 +112,10 @@
<Compile Include="Http\HttpCommaSeparatedField.cs" />
<Compile Include="Http\HttpCommaSeparatedInnerField.cs" />
<Compile Include="Http\HttpContentLengthField.cs" />
<Compile Include="Http\HttpContentTypeField.cs" />
<Compile Include="Http\HttpDatagram.cs" />
<Compile Include="Http\HttpField.cs" />
<Compile Include="Http\HttpFieldParameters.cs" />
<Compile Include="Http\HttpHeader.cs" />
<Compile Include="Http\HttpParser.cs" />
<Compile Include="Http\HttpRegex.cs" />
......
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