// /** // * 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.type; 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 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(); 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 offsets = new List(); List validated = new List(); 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 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(); } } }