| Index: third_party/grpc/src/csharp/Grpc.Core/Metadata.cs
|
| diff --git a/third_party/grpc/src/csharp/Grpc.Core/Metadata.cs b/third_party/grpc/src/csharp/Grpc.Core/Metadata.cs
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aa22f840d6c31a03dc7fc690ab99900067b05272
|
| --- /dev/null
|
| +++ b/third_party/grpc/src/csharp/Grpc.Core/Metadata.cs
|
| @@ -0,0 +1,333 @@
|
| +#region Copyright notice and license
|
| +// Copyright 2015-2016, Google Inc.
|
| +// All rights reserved.
|
| +//
|
| +// Redistribution and use in source and binary forms, with or without
|
| +// modification, are permitted provided that the following conditions are
|
| +// met:
|
| +//
|
| +// * Redistributions of source code must retain the above copyright
|
| +// notice, this list of conditions and the following disclaimer.
|
| +// * Redistributions in binary form must reproduce the above
|
| +// copyright notice, this list of conditions and the following disclaimer
|
| +// in the documentation and/or other materials provided with the
|
| +// distribution.
|
| +// * Neither the name of Google Inc. nor the names of its
|
| +// contributors may be used to endorse or promote products derived from
|
| +// this software without specific prior written permission.
|
| +//
|
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| +#endregion
|
| +
|
| +using System;
|
| +using System.Collections;
|
| +using System.Collections.Generic;
|
| +using System.Collections.Specialized;
|
| +using System.Globalization;
|
| +using System.Runtime.InteropServices;
|
| +using System.Text;
|
| +using System.Text.RegularExpressions;
|
| +
|
| +using Grpc.Core.Utils;
|
| +
|
| +namespace Grpc.Core
|
| +{
|
| + /// <summary>
|
| + /// A collection of metadata entries that can be exchanged during a call.
|
| + /// gRPC supports these types of metadata:
|
| + /// <list type="bullet">
|
| + /// <item><term>Request headers</term><description>are sent by the client at the beginning of a remote call before any request messages are sent.</description></item>
|
| + /// <item><term>Response headers</term><description>are sent by the server at the beginning of a remote call handler before any response messages are sent.</description></item>
|
| + /// <item><term>Response trailers</term><description>are sent by the server at the end of a remote call along with resulting call status.</description></item>
|
| + /// </list>
|
| + /// </summary>
|
| + public sealed class Metadata : IList<Metadata.Entry>
|
| + {
|
| + /// <summary>
|
| + /// All binary headers should have this suffix.
|
| + /// </summary>
|
| + public const string BinaryHeaderSuffix = "-bin";
|
| +
|
| + /// <summary>
|
| + /// An read-only instance of metadata containing no entries.
|
| + /// </summary>
|
| + public static readonly Metadata Empty = new Metadata().Freeze();
|
| +
|
| + readonly List<Entry> entries;
|
| + bool readOnly;
|
| +
|
| + /// <summary>
|
| + /// Initializes a new instance of <c>Metadata</c>.
|
| + /// </summary>
|
| + public Metadata()
|
| + {
|
| + this.entries = new List<Entry>();
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Makes this object read-only.
|
| + /// </summary>
|
| + /// <returns>this object</returns>
|
| + internal Metadata Freeze()
|
| + {
|
| + this.readOnly = true;
|
| + return this;
|
| + }
|
| +
|
| + // TODO: add support for access by key
|
| +
|
| + #region IList members
|
| +
|
| + public int IndexOf(Metadata.Entry item)
|
| + {
|
| + return entries.IndexOf(item);
|
| + }
|
| +
|
| + public void Insert(int index, Metadata.Entry item)
|
| + {
|
| + CheckWriteable();
|
| + entries.Insert(index, item);
|
| + }
|
| +
|
| + public void RemoveAt(int index)
|
| + {
|
| + CheckWriteable();
|
| + entries.RemoveAt(index);
|
| + }
|
| +
|
| + public Metadata.Entry this[int index]
|
| + {
|
| + get
|
| + {
|
| + return entries[index];
|
| + }
|
| +
|
| + set
|
| + {
|
| + CheckWriteable();
|
| + entries[index] = value;
|
| + }
|
| + }
|
| +
|
| + public void Add(Metadata.Entry item)
|
| + {
|
| + CheckWriteable();
|
| + entries.Add(item);
|
| + }
|
| +
|
| + public void Add(string key, string value)
|
| + {
|
| + Add(new Entry(key, value));
|
| + }
|
| +
|
| + public void Add(string key, byte[] valueBytes)
|
| + {
|
| + Add(new Entry(key, valueBytes));
|
| + }
|
| +
|
| + public void Clear()
|
| + {
|
| + CheckWriteable();
|
| + entries.Clear();
|
| + }
|
| +
|
| + public bool Contains(Metadata.Entry item)
|
| + {
|
| + return entries.Contains(item);
|
| + }
|
| +
|
| + public void CopyTo(Metadata.Entry[] array, int arrayIndex)
|
| + {
|
| + entries.CopyTo(array, arrayIndex);
|
| + }
|
| +
|
| + public int Count
|
| + {
|
| + get { return entries.Count; }
|
| + }
|
| +
|
| + public bool IsReadOnly
|
| + {
|
| + get { return readOnly; }
|
| + }
|
| +
|
| + public bool Remove(Metadata.Entry item)
|
| + {
|
| + CheckWriteable();
|
| + return entries.Remove(item);
|
| + }
|
| +
|
| + public IEnumerator<Metadata.Entry> GetEnumerator()
|
| + {
|
| + return entries.GetEnumerator();
|
| + }
|
| +
|
| + IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
| + {
|
| + return entries.GetEnumerator();
|
| + }
|
| +
|
| + private void CheckWriteable()
|
| + {
|
| + GrpcPreconditions.CheckState(!readOnly, "Object is read only");
|
| + }
|
| +
|
| + #endregion
|
| +
|
| + /// <summary>
|
| + /// Metadata entry
|
| + /// </summary>
|
| + public struct Entry
|
| + {
|
| + private static readonly Encoding Encoding = Encoding.ASCII;
|
| + private static readonly Regex ValidKeyRegex = new Regex("^[a-z0-9_-]+$");
|
| +
|
| + readonly string key;
|
| + readonly string value;
|
| + readonly byte[] valueBytes;
|
| +
|
| + private Entry(string key, string value, byte[] valueBytes)
|
| + {
|
| + this.key = key;
|
| + this.value = value;
|
| + this.valueBytes = valueBytes;
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Initializes a new instance of the <see cref="Grpc.Core.Metadata.Entry"/> struct with a binary value.
|
| + /// </summary>
|
| + /// <param name="key">Metadata key, needs to have suffix indicating a binary valued metadata entry.</param>
|
| + /// <param name="valueBytes">Value bytes.</param>
|
| + public Entry(string key, byte[] valueBytes)
|
| + {
|
| + this.key = NormalizeKey(key);
|
| + GrpcPreconditions.CheckArgument(this.key.EndsWith(BinaryHeaderSuffix),
|
| + "Key for binary valued metadata entry needs to have suffix indicating binary value.");
|
| + this.value = null;
|
| + GrpcPreconditions.CheckNotNull(valueBytes, "valueBytes");
|
| + this.valueBytes = new byte[valueBytes.Length];
|
| + Buffer.BlockCopy(valueBytes, 0, this.valueBytes, 0, valueBytes.Length); // defensive copy to guarantee immutability
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Initializes a new instance of the <see cref="Grpc.Core.Metadata.Entry"/> struct holding an ASCII value.
|
| + /// </summary>
|
| + /// <param name="key">Metadata key, must not use suffix indicating a binary valued metadata entry.</param>
|
| + /// <param name="value">Value string. Only ASCII characters are allowed.</param>
|
| + public Entry(string key, string value)
|
| + {
|
| + this.key = NormalizeKey(key);
|
| + GrpcPreconditions.CheckArgument(!this.key.EndsWith(BinaryHeaderSuffix),
|
| + "Key for ASCII valued metadata entry cannot have suffix indicating binary value.");
|
| + this.value = GrpcPreconditions.CheckNotNull(value, "value");
|
| + this.valueBytes = null;
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Gets the metadata entry key.
|
| + /// </summary>
|
| + public string Key
|
| + {
|
| + get
|
| + {
|
| + return this.key;
|
| + }
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Gets the binary value of this metadata entry.
|
| + /// </summary>
|
| + public byte[] ValueBytes
|
| + {
|
| + get
|
| + {
|
| + if (valueBytes == null)
|
| + {
|
| + return Encoding.GetBytes(value);
|
| + }
|
| +
|
| + // defensive copy to guarantee immutability
|
| + var bytes = new byte[valueBytes.Length];
|
| + Buffer.BlockCopy(valueBytes, 0, bytes, 0, valueBytes.Length);
|
| + return bytes;
|
| + }
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Gets the string value of this metadata entry.
|
| + /// </summary>
|
| + public string Value
|
| + {
|
| + get
|
| + {
|
| + GrpcPreconditions.CheckState(!IsBinary, "Cannot access string value of a binary metadata entry");
|
| + return value ?? Encoding.GetString(valueBytes);
|
| + }
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Returns <c>true</c> if this entry is a binary-value entry.
|
| + /// </summary>
|
| + public bool IsBinary
|
| + {
|
| + get
|
| + {
|
| + return value == null;
|
| + }
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Returns a <see cref="System.String"/> that represents the current <see cref="Grpc.Core.Metadata.Entry"/>.
|
| + /// </summary>
|
| + public override string ToString()
|
| + {
|
| + if (IsBinary)
|
| + {
|
| + return string.Format("[Entry: key={0}, valueBytes={1}]", key, valueBytes);
|
| + }
|
| +
|
| + return string.Format("[Entry: key={0}, value={1}]", key, value);
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Gets the serialized value for this entry. For binary metadata entries, this leaks
|
| + /// the internal <c>valueBytes</c> byte array and caller must not change contents of it.
|
| + /// </summary>
|
| + internal byte[] GetSerializedValueUnsafe()
|
| + {
|
| + return valueBytes ?? Encoding.GetBytes(value);
|
| + }
|
| +
|
| + /// <summary>
|
| + /// Creates a binary value or ascii value metadata entry from data received from the native layer.
|
| + /// We trust C core to give us well-formed data, so we don't perform any checks or defensive copying.
|
| + /// </summary>
|
| + internal static Entry CreateUnsafe(string key, byte[] valueBytes)
|
| + {
|
| + if (key.EndsWith(BinaryHeaderSuffix))
|
| + {
|
| + return new Entry(key, null, valueBytes);
|
| + }
|
| + return new Entry(key, Encoding.GetString(valueBytes), null);
|
| + }
|
| +
|
| + private static string NormalizeKey(string key)
|
| + {
|
| + var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLower(CultureInfo.InvariantCulture);
|
| + GrpcPreconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized),
|
| + "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens.");
|
| + return normalized;
|
| + }
|
| + }
|
| + }
|
| +}
|
|
|