// Copyright © 2020 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; using System.Collections.Generic; using System.Linq; namespace CefSharp.DevTools.Network { /// /// Request / response headers as keys / values of JSON object. /// /// /// CDP uses comma seperated values to store multiple header values. /// Use or to get a string[] /// for headers that have multiple values. /// /// Helper methods for dealing with comma separated header values based on https://github.com/dotnet/aspnetcore/blob/52eff90fbcfca39b7eb58baad597df6a99a542b0/src/Http/Http.Abstractions/src/Extensions/HeaderDictionaryExtensions.cs public class Headers : Dictionary { /// /// Initializes a new instance of the Headers class. /// public Headers() : base(StringComparer.OrdinalIgnoreCase) { } /// /// Returns itself /// /// Dictionary of headers public Dictionary ToDictionary() { return this; } /// /// Gets an array of values for the specified key. Values are comma seperated and will be split into a string[]. /// Quoted values will not be split, and the quotes will be removed. /// /// The header name. /// the associated values from the dictionary separated into individual values, or null if the key is not present. /// true if the Dictionary contains an element with the specified key; otherwise, false. public bool TryGetValues(string key, out string[] values) { values = null; string value; if (TryGetValue(key, out value)) { var list = new List(); var valueStartIndex = -1; var valueEndIndex = -1; var inQuote = false; for (var i = 0; i < value.Length; i++) { var c = value[i]; if (c == '\"') { inQuote = !inQuote; continue; } if (!inQuote && char.IsWhiteSpace(c)) { continue; } if (valueStartIndex == -1) { valueStartIndex = i; } if (!inQuote && c == ',') { if (valueEndIndex == -1) { list.Add(string.Empty); } else { list.Add(value.Substring(valueStartIndex, valueEndIndex + 1 - valueStartIndex)); } valueStartIndex = -1; valueEndIndex = -1; continue; } valueEndIndex = i; } if (valueEndIndex == -1) { list.Add(string.Empty); } else { list.Add(value.Substring(valueStartIndex, valueEndIndex + 1 - valueStartIndex)); } values = list.ToArray(); return true; } return false; } /// /// Get the associated values from the dictionary separated into individual values. /// Quoted values will not be split, and the quotes will be removed. /// /// The header name. /// the associated values from the dictionary separated into individual values, or null if the key is not present. public string[] GetCommaSeparatedValues(string key) { string[] values; if (TryGetValues(key, out values)) { return values; } return null; } /// /// Quotes any values containing commas, and then comma joins all of the values with any existing values. /// /// The header name. /// The header values. public void AppendCommaSeparatedValues(string key, params string[] values) { if (TryGetValue(key, out var existingValue)) { this[key] = existingValue + "," + string.Join(",", values.Select(QuoteIfNeeded)); } else { SetCommaSeparatedValues(key, values); } } /// /// Quotes any values containing commas, and then comma joins all of the values. /// /// The header name. /// The header values. public void SetCommaSeparatedValues(string key, params string[] values) { this[key] = string.Join(",", values.Select(QuoteIfNeeded)); } private static string QuoteIfNeeded(string value) { if (!string.IsNullOrEmpty(value) && value.Contains(',') && (value[0] != '"' || value[value.Length - 1] != '"')) { return "\"" + value + "\""; } return value; } } }