// 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;
}
}
}