ln.http/message/Message.cs

154 lines
4.6 KiB
C#

// /**
// * File: Message.cs
// * Author: haraldwolff
// *
// * This file and it's content is copyrighted by the Author and / or copyright holder.
// * Any use wihtout proper permission is illegal and may lead to legal actions.
// *
// *
// **/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Globalization;
using ln.http.io;
using ln.types;
using ln.http.message.parser;
namespace ln.http.message
{
public class Message
{
public HeaderContainer Headers { get; private set; }
byte[] bodyData;
int bodyOffset;
int bodyLength;
List<Message> parts;
bool isMultipart;
public bool IsMultipart => isMultipart;
public Message()
{
Setup(new HeaderContainer(), new byte[0], 0, 0);
}
public Message(HeaderContainer headers, byte[] body)
: this(headers, body, 0, body.Length) { }
public Message(HeaderContainer headers, byte[] body, int offset, int length)
{
Setup(headers, body, offset, length);
}
public Message(byte[] body, int offset, int length)
{
MemoryStream memoryStream = new MemoryStream(body, offset, length);
HeaderContainer headers = MIME.ReadHeader(new UnbufferedStreamReader(memoryStream));
if (memoryStream.Position >= length)
throw new FormatException("MIME header section too long");
Setup(headers, body, offset + (int)memoryStream.Position, length - (int)memoryStream.Position);
}
public Message(Stream stream)
{
HeaderContainer headers = MIME.ReadHeader(new UnbufferedStreamReader(stream));
byte[] data = stream.ReadToEnd();
Setup(headers, data, 0, data.Length);
}
private void Setup(HeaderContainer headers, byte[] body, int offset, int length)
{
Headers = headers;
bodyData = body;
bodyOffset = offset;
bodyLength = length;
string ct = Headers["Content-Type"].Value;
isMultipart = ct.StartsWith("multipart/", StringComparison.InvariantCulture) || ct.StartsWith("message/", StringComparison.InvariantCulture);
}
public void ReadParts()
{
parts = new List<Message>();
if (isMultipart)
{
string boundary = Headers["Content-Type"].GetParameter("boundary");
string delimiter = "--" + boundary;
int[] indeces = FindIndeces(bodyData, bodyOffset, bodyLength, Encoding.ASCII.GetBytes(delimiter));
for (int n = 1; n < indeces.Length; n++)
{
Message part = new Message(bodyData, indeces[n - 1], indeces[n] - indeces[n - 1]);
parts.Add(part);
}
}
}
int[] FindIndeces(byte[] data,int offset,int length,byte[] pattern)
{
List<int> offsets = new List<int>();
List<int> validated = new List<int>();
for (int n = offset; n < (length - pattern.Length); n++)
{
int p = 0;
while ((p < pattern.Length) && (data[n + p] == pattern[p]))
p++;
if (p == pattern.Length)
{
if ((n == offset) || ((n >= (offset + 2)) && (data[offset + n - 2] == '\r') && (data[offset + n - 1] == '\n')))
{
n += pattern.Length;
while ((n < (offset + length)) && (data[n - 2] != '\r') && (data[n - 1] != '\n'))
n++;
validated.Add(n);
if (((offset + length) > (n + 1)) && (data[n] == '-') && (data[n + 1] == '-'))
break;
}
}
}
return validated.ToArray();
}
public Stream OpenBodyStream() => new MemoryStream(bodyData, bodyOffset, bodyLength);
public IEnumerable<Message> Parts
{
get
{
if (parts == null)
ReadParts();
return parts;
}
}
public bool HasHeader(string name) => Headers.Contains(name);
public Header GetHeader(string name) => Headers[name];
public void SetHeader(string name, string value) => Headers.Set(name, value);
public void RemoveHeader(String name) => Headers.Remove(name);
public override string ToString()
{
return base.ToString();
}
}
}