using System; using System.Collections; using System.Collections.Generic; namespace OSHttpServer { /// /// represents a HTTP input item. Each item can have multiple sub items, a sub item /// is made in a HTML form by using square brackets /// /// /// // becomes: /// Console.WriteLine("Value: {0}", form["user"]["FirstName"].Value); /// /// /// All names in a form SHOULD be in lowercase. /// public class HttpInputItem : IHttpInput { /// Representation of a non-initialized . public static readonly HttpInputItem Empty = new(string.Empty, true); private readonly IDictionary _items = new Dictionary(); private readonly List _values = new(); private string _name; private readonly bool _ignoreChanges; /// /// Initializes an input item setting its name/identifier and value /// /// Parameter name/id /// Parameter value public HttpInputItem(string name, string value) { Name = name; Add(value); } private HttpInputItem(string name, bool ignore) { Name = name; _ignoreChanges = ignore; } /// Creates a deep copy of the item specified /// The item to copy /// The function makes a deep copy of quite a lot which can be slow public HttpInputItem(HttpInputItem item) { foreach (KeyValuePair pair in item._items) _items.Add(pair.Key, pair.Value); foreach (string value in item._values) _values.Add(value); _ignoreChanges = item._ignoreChanges; _name = item.Name; } /// /// Number of values /// public int Count { get { return _values.Count; } } /// /// Get a sub item /// /// name in lower case. /// if no item was found. public HttpInputItem this[string name] { get { return _items.TryGetValue(name, out HttpInputItem hii) ? hii : Empty; } } /// /// Name of item (in lower case). /// public string Name { get { return _name; } set { _name = value; } } /// /// Returns the first value, or null if no value exist. /// public string Value { get { return _values.Count == 0 ? null : _values[0]; } set { if (_values.Count == 0) _values.Add(value); else _values[0] = value; } } /// /// Returns the last value, or null if no value exist. /// public string LastValue { get { return _values.Count == 0 ? null : _values[^1]; } } /// /// Returns the list with values. /// public IList Values { get { return _values.AsReadOnly(); } } /// /// Add another value to this item /// /// Value to add. /// Cannot add stuff to . public void Add(string value) { if (value is null) return; if (_ignoreChanges) throw new InvalidOperationException("Cannot add stuff to HttpInput.Empty."); _values.Add(value); } /// /// checks if a sub-item exists (and has a value). /// /// name in lower case /// true if the sub-item exists and has a value; otherwise false. public bool Contains(string name) { return _items.TryGetValue(name, out HttpInputItem hii) && hii.Value != null; } /// Returns a formatted representation of the instance with the values of all contained parameters public override string ToString() { return ToString(string.Empty); } /// /// Outputs the string in a formatted manner /// /// A prefix to append, used internally /// produce a query string public string ToString(string prefix, bool asQuerySting) { string name; if (string.IsNullOrEmpty(prefix)) name = Name; else name = prefix + "[" + Name + "]"; if (asQuerySting) { string temp; if (_values.Count == 0 && _items.Count > 0) temp = string.Empty; else temp = name; if (_values.Count > 0) { temp += '='; foreach (string value in _values) temp += value + ','; temp = temp.Remove(temp.Length - 1, 1); } foreach (KeyValuePair item in _items) temp += item.Value.ToString(name, true) + '&'; return _items.Count > 0 ? temp[..^1] : temp; } else { string temp = name; if (_values.Count > 0) { temp += " = "; foreach (string value in _values) temp += value + ", "; temp = temp.Remove(temp.Length - 2, 2); } temp += Environment.NewLine; foreach (KeyValuePair item in _items) temp += item.Value.ToString(name, false); return temp; } } #region IHttpInput Members /// /// /// /// name in lower case /// HttpInputItem IHttpInput.this[string name] { get { return _items.TryGetValue(name, out HttpInputItem hii) ? hii : Empty; } } /// /// Add a sub item. /// /// Can contain array formatting, the item is then parsed and added in multiple levels /// Value to add. /// Argument is null. /// Cannot add stuff to . public void Add(string name, string value) { if (name == null && value != null) throw new ArgumentNullException("name"); if (name == null) return; if (_ignoreChanges) throw new InvalidOperationException("Cannot add stuff to HttpInput.Empty."); int pos = name.IndexOf('['); if (pos != -1) { string name1 = name[..pos]; string name2 = HttpInput.ExtractOne(name); if (!_items.TryGetValue(name1, out HttpInputItem it)) { it = new HttpInputItem(name1, null); _items.Add(name1, it); } it.Add(name2, value); /* HttpInputItem item = HttpInput.ParseItem(name, value); // Add the value to an existing sub item if (_items.ContainsKey(item.Name)) _items[item.Name].Add(item.Value); else _items.Add(item.Name, item); */ } else { if (_items.TryGetValue(name, out HttpInputItem it2)) it2.Add(value); else _items.Add(name, new HttpInputItem(name, value)); } } #endregion /// ///Returns an enumerator that iterates through the collection. /// /// /// ///A that can be used to iterate through the collection. /// ///1 IEnumerator IEnumerable.GetEnumerator() { return _items.Values.GetEnumerator(); } #region IEnumerable Members /// ///Returns an enumerator that iterates through a collection. /// /// /// ///An object that can be used to iterate through the collection. /// ///2 public IEnumerator GetEnumerator() { return _items.Values.GetEnumerator(); } #endregion /// /// Outputs the string in a formatted manner /// /// A prefix to append, used internally /// public string ToString(string prefix) { return ToString(prefix, false); } } }