using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; namespace Apewer.Network { /// <summary>HTTP 头的集合。</summary> [Serializable] public sealed class HttpHeaders : IEnumerable<HttpHeader>, ICollection<HttpHeader>, IToJson { #region IEnumerable List<HttpHeader> _list = new List<HttpHeader>(); long _version = 0L; /// <summary>获取枚举器。</summary> public IEnumerator<HttpHeader> GetEnumerator() => new Enumerator(this); /// <summary>获取枚举器。</summary> IEnumerator IEnumerable.GetEnumerator() => new Enumerator(this); /// <summary></summary> public sealed class Enumerator : IEnumerator<HttpHeader> { HttpHeaders _headeres = null; long _version = 0L; bool _disposed = false; HttpHeader _current = null; int _index = 0; const string ObjectName = nameof(Enumerator); const string OriginChanged = "原集合已变更,无法继续遍历。"; /// <summary></summary> public HttpHeader Current { get { if (_disposed) throw new ObjectDisposedException(ObjectName); if (_version != _headeres._version) throw new InvalidOperationException(OriginChanged); return _current; } } /// <summary></summary> object IEnumerator.Current { get => Current; } /// <summary></summary> public void Dispose() { _disposed = true; } /// <summary></summary> public bool MoveNext() { if (_disposed) throw new ObjectDisposedException(ObjectName); if (_version != _headeres._version) throw new InvalidOperationException(OriginChanged); if (_index < _headeres._list.Count) { _current = _headeres._list[_index]; _index++; return true; } return false; } /// <summary></summary> public void Reset() { _current = null; _index = 0; } /// <exception cref="ArgumentNullException" /> public Enumerator(HttpHeaders headers) { if (headers == null) throw new ArgumentNullException(nameof(headers)); _headeres = headers; _version = headers._version; Reset(); } } #endregion #region ICollection /// <summary>元素数量。</summary> public int Count { get => _list.Count; } /// <summary>当前集合是只读。</summary> public bool IsReadOnly { get => false; } /// <summary>添加一项。</summary> /// <exception cref="ArgumentNullException" /> public HttpHeader Add(string name, string value) { if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); var header = new HttpHeader(name, value); _list.Add(header); _version++; return header; } /// <summary>添加一项。</summary> /// <exception cref="ArgumentNullException" /> public void Add(HttpHeader header) { if (header == null) throw new ArgumentNullException(nameof(header)); _list.Add(header); _version++; } /// <summary>移除所有元素。</summary> public void Clear() => _list.Clear(); /// <summary>判断是否包含指定的元素。</summary> public bool Contains(HttpHeader item) => _list.Contains(item); /// <summary>复制所有元素到数组。</summary> /// <param name="array">目标数组。</param> /// <param name="arrayIndex">数组的位置。</param> /// <exception cref="ArgumentNullException" /> /// <exception cref="ArgumentOutOfRangeException" /> /// <exception cref="ArgumentException" /> public void CopyTo(HttpHeader[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex); /// <summary>移除指定的元素</summary> public bool Remove(HttpHeader item) => _list.Remove(item); #endregion #region IList /// <summary></summary> /// <exception cref="ArgumentOutOfRangeException" /> public HttpHeader this[int index] { get => _list[index]; set => _list[index] = value; } /// <summary></summary> /// <exception cref="ArgumentOutOfRangeException" /> public string this[string name] { get => GetValue(name); set => SetValue(name, value); } /// <summary>搜索指定对象在当前集合中的位置索引。</summary> public int IndexOf(HttpHeader item) => _list.IndexOf(item); /// <summary>插入元素到指定位置。</summary> /// <exception cref="ArgumentOutOfRangeException" /> public void Insert(int index, HttpHeader item) => _list.Insert(index, item); /// <summary>移除指定位置的元素。</summary> /// <exception cref="ArgumentOutOfRangeException" /> public void RemoveAt(int index) => _list.RemoveAt(index); #endregion #region constructor /// <summary></summary> public HttpHeaders() { } /// <summary></summary> /// <exception cref="ArgumentNullException" /> public HttpHeaders(params HttpHeader[] headers) : this(headers as IEnumerable<HttpHeader>) { } /// <summary></summary> /// <exception cref="ArgumentNullException" /> public HttpHeaders(IEnumerable<HttpHeader> headers) { if (headers == null) throw new ArgumentNullException(nameof(headers)); foreach (var header in headers) { if (header == null) continue; if (header.Name.IsEmpty()) continue; Add(header); } } /// <summary></summary> /// <exception cref="ArgumentNullException" /> public HttpHeaders(IEnumerable<KeyValuePair<string, string>> headers) { if (headers == null) return; foreach (var header in headers) { if (header.Key.IsEmpty()) continue; Add(header.Key, header.Value); } } /// <summary></summary> /// <exception cref="ArgumentNullException" /> public HttpHeaders(NameValueCollection headers) { if (headers == null) return; var keys = headers.AllKeys; foreach (var key in keys) { if (key.IsEmpty()) continue; var value = headers[key]; Add(key, value); } } #endregion #region operation /// <summary>获取所有名称。</summary> public string[] GetNames() { var names = new List<string>(); var count = _list.Count; for (var i = 0; i < count; i++) { var name = _list[i].Name; if (string.IsNullOrEmpty(name)) continue; if (names.Contains(name)) continue; names.Add(name); } names.Sort(); return names.ToArray(); } /// <summary>获取匹配 Name 的 Value。不存在 Name 时返回 NULL 值。</summary> /// <exception cref="ArgumentNullException" /> public string GetValue(string name) { if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); // 精准匹配。 var count = _list.Count; for (var i = 0; i < count; i++) { var item = _list[i]; if (string.IsNullOrEmpty(item.Name)) continue; if (item.Name == name) { if (string.IsNullOrEmpty(item.Value)) continue; return item.Value; } } // 忽略大小写。 var lower = TextUtility.Lower(name); for (var i = 0; i < count; i++) { var item = _list[i]; if (string.IsNullOrEmpty(item.Name)) continue; if (TextUtility.Lower(item.Name) == lower) { if (string.IsNullOrEmpty(item.Value)) continue; return item.Value; } } return null; } /// <summary>获取匹配 Name 的 Value。不存在 Name 时返回 NULL 值。</summary> /// <exception cref="ArgumentNullException" /> public string[] GetValues(string name) { if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); // 忽略大小写。 // name = TextUtility.Lower(name); var count = _list.Count; var values = new List<string>(_list.Count); for (var i = 0; i < count; i++) { var item = _list[i]; if (string.IsNullOrEmpty(item.Name)) continue; if (string.Equals(item.Name, name, StringComparison.CurrentCultureIgnoreCase)) { var value = item.Value.ToTrim(); if (string.IsNullOrEmpty(value)) continue; values.Add(value); } } return values.ToArray(); } /// <summary>设置 Name 的 Value。不存在 Name 时添加新元素。</summary> /// <exception cref="ArgumentNullException" /> public HttpHeader SetValue(string name, string value) { if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); // 尝试精准匹配。 var count = _list.Count; for (var i = 0; i < count; i++) { var item = _list[i]; if (string.IsNullOrEmpty(item.Name)) continue; if (item.Name == name) { item.Value = value; _version++; return item; } } // 尝试模糊匹配。 var lower = TextUtility.Lower(name); for (var i = 0; i < count; i++) { var item = _list[i]; if (TextUtility.Lower(item.Name) == lower) { item.Value = value; _version++; return item; } } // 添加新项。 return Add(name, value); } /// <summary>每个元素组成为新数组。</summary> public HttpHeader[] ToArray() => _list.ToArray(); /// <summary></summary> public override string ToString() => $"Count = {_list.Count}"; #endregion #region Json internal HttpHeaders(Json json) { if (!json) return; if (json.IsObject) { var properties = json.GetProperties(); foreach (var property in properties) { if (property == null) continue; if (property.Name.IsEmpty()) continue; Add(property.Name, property.Value?.ToString()); } } if (json.IsArray) { var array = json.Array<HttpHeader>(); if (array != null) { for (var i = 0; i < array.Length; i++) { if (array[i] == null) continue; if (array[i].Name.IsEmpty()) continue; _list.Add(array[i]); } } } } /// <summary></summary> public Json ToJson() { var array = Json.NewArray(); var count = 0; for (var i = 0; i < count; i++) { var item = Json.From(_list[i]); array.AddItem(item); } return array; } #endregion } }