AngleSharp by Florian Rappl

<PackageReference Include="AngleSharp" Version="0.9.0" />

 FormDataSet

sealed class FormDataSet : IEnumerable<string>, IEnumerable
Bundles information stored in HTML forms.
using AngleSharp.Dom.Io; using AngleSharp.Extensions; using AngleSharp.Network; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace AngleSharp.Html { internal sealed class FormDataSet : IEnumerable<string>, IEnumerable { private abstract class FormDataSetEntry { private readonly string _name; private readonly string _type; public bool HasName => _name != null; public string Name => _name ?? string.Empty; public string Type => _type ?? InputTypeNames.Text; public FormDataSetEntry(string name, string type) { _name = name; _type = type; } public abstract Action<StreamWriter> AsMultipart(Encoding encoding); public abstract Tuple<string, string> AsPlaintext(); public abstract Tuple<string, string> AsUrlEncoded(Encoding encoding); public abstract bool Contains(string boundary, Encoding encoding); } private sealed class TextDataSetEntry : FormDataSetEntry { private readonly string _value; public bool HasValue => _value != null; public string Value => _value; public TextDataSetEntry(string name, string value, string type) : base(name, type) { _value = value; } public override bool Contains(string boundary, Encoding encoding) { if (_value == null) return false; return _value.Contains(boundary); } public override Action<StreamWriter> AsMultipart(Encoding encoding) { if (base.HasName && HasValue) return delegate(StreamWriter stream) { stream.WriteLine("Content-Disposition: form-data; name=\"" + base.Name.HtmlEncode(encoding) + "\""); stream.WriteLine(); stream.WriteLine(_value.HtmlEncode(encoding)); }; return null; } public override Tuple<string, string> AsPlaintext() { if (base.HasName && HasValue) return Tuple.Create(base.Name, _value); return null; } public override Tuple<string, string> AsUrlEncoded(Encoding encoding) { if (base.HasName && HasValue) { byte[] bytes = encoding.GetBytes(base.Name); byte[] bytes2 = encoding.GetBytes(_value); return Tuple.Create(bytes.UrlEncode(), bytes2.UrlEncode()); } return null; } } private sealed class FileDataSetEntry : FormDataSetEntry { private readonly IFile _value; public bool HasValue { get { if (_value != null) return _value.Name != null; return false; } } public bool HasValueBody { get { if (_value != null && _value.Body != null) return _value.Type != null; return false; } } public IFile Value => _value; public string FileName { get { if (_value == null) return string.Empty; return _value.Name; } } public string ContentType { get { if (_value == null) return MimeTypes.Binary; return _value.Type; } } public FileDataSetEntry(string name, IFile value, string type) : base(name, type) { _value = value; } public override bool Contains(string boundary, Encoding encoding) { if (_value == null || _value.Body == null) return false; return false; } public override Action<StreamWriter> AsMultipart(Encoding encoding) { if (base.HasName) return delegate(StreamWriter stream) { bool flag = HasValue && HasValueBody; stream.WriteLine("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", new object[2] { base.Name.HtmlEncode(encoding), FileName.HtmlEncode(encoding) }); stream.WriteLine("Content-Type: " + ContentType); stream.WriteLine(); if (flag) { stream.Flush(); _value.Body.CopyTo(stream.BaseStream); } stream.WriteLine(); }; return null; } public override Tuple<string, string> AsPlaintext() { if (base.HasName && HasValue) return Tuple.Create(base.Name, _value.Name); return null; } public override Tuple<string, string> AsUrlEncoded(Encoding encoding) { if (base.HasName && HasValue) { byte[] bytes = encoding.GetBytes(base.Name); byte[] bytes2 = encoding.GetBytes(_value.Name); return Tuple.Create(bytes.UrlEncode(), bytes2.UrlEncode()); } return null; } } private readonly List<FormDataSetEntry> _entries; private string _boundary; private static readonly string[] NewLines = new string[3] { "\r\n", "\r", "\n" }; public string Boundary => _boundary; public FormDataSet() { _boundary = Guid.NewGuid().ToString(); _entries = new List<FormDataSetEntry>(); } public Stream AsMultipart(Encoding encoding = null) { return Build(encoding, delegate(StreamWriter stream) { Encoding enc = stream.Encoding; IEnumerable<Action<StreamWriter>> enumerable = from m in _entries select m.AsMultipart(enc) into m where m != null select m; foreach (Action<StreamWriter> item in enumerable) { stream.Write("--"); stream.WriteLine(_boundary); item(stream); } stream.Write("--"); stream.Write(_boundary); stream.Write("--"); }); } public Stream AsUrlEncoded(Encoding encoding = null) { return Build(encoding, delegate(StreamWriter stream) { int num = 0; Encoding enc = stream.Encoding; if (num < _entries.Count && _entries[num].HasName && _entries[num].Name.Equals(Tags.IsIndex) && _entries[num].Type.Equals(InputTypeNames.Text, StringComparison.OrdinalIgnoreCase)) { stream.Write(((TextDataSetEntry)_entries[num]).Value); num++; } Tuple<string, string>[] array = (from m in _entries.Skip(num) select m.AsUrlEncoded(enc) into m where m != null select m).ToArray(); for (int i = 0; i < array.Length; i++) { if (i > 0) stream.Write('&'); stream.Write(array[i].Item1); stream.Write('='); stream.Write(array[i].Item2); } }); } public Stream AsPlaintext(Encoding encoding = null) { return Build(encoding, delegate(StreamWriter stream) { Tuple<string, string>[] array = (from m in _entries select m.AsPlaintext() into m where m != null select m).ToArray(); for (int i = 0; i < array.Length; i++) { if (i > 0) stream.Write("\r\n"); stream.Write(array[i].Item1); stream.Write('='); stream.Write(array[i].Item2); } }); } public void Append(string name, string value, string type) { if (string.Compare(type, Tags.Textarea, StringComparison.OrdinalIgnoreCase) == 0) { name = Normalize(name); value = Normalize(value); } _entries.Add(new TextDataSetEntry(name, value, type)); } public void Append(string name, IFile value, string type) { if (string.Compare(type, InputTypeNames.File, StringComparison.OrdinalIgnoreCase) == 0) name = Normalize(name); _entries.Add(new FileDataSetEntry(name, value, type)); } private Stream Build(Encoding encoding, Action<StreamWriter> process) { encoding = (encoding ?? TextEncoding.Utf8); MemoryStream memoryStream = new MemoryStream(); CheckBoundaries(encoding); ReplaceCharset(encoding); StreamWriter streamWriter = new StreamWriter(memoryStream, encoding); process(streamWriter); streamWriter.Flush(); memoryStream.Position = 0; return memoryStream; } private void ReplaceCharset(Encoding encoding) { for (int i = 0; i < _entries.Count; i++) { FormDataSetEntry formDataSetEntry = _entries[i]; if (!string.IsNullOrEmpty(formDataSetEntry.Name) && formDataSetEntry.Name.Equals("_charset_") && formDataSetEntry.Type.Equals(InputTypeNames.Hidden, StringComparison.OrdinalIgnoreCase)) _entries[i] = new TextDataSetEntry(formDataSetEntry.Name, encoding.WebName, formDataSetEntry.Type); } } private void CheckBoundaries(Encoding encoding) { bool flag = false; do { for (int i = 0; i < _entries.Count; i++) { if (flag = _entries[i].Contains(_boundary, encoding)) { _boundary = Guid.NewGuid().ToString(); break; } } } while (flag); } private static string Normalize(string value) { if (!string.IsNullOrEmpty(value)) { string[] value2 = value.Split(NewLines, StringSplitOptions.None); return string.Join("\r\n", value2); } return value; } public IEnumerator<string> GetEnumerator() { return (from m in _entries select m.Name).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }