internal static HeaderType Validate(int streamId, ICharSequence name, HeaderType?previousHeaderType) { if (PseudoHeaderName.HasPseudoHeaderFormat(name)) { if (previousHeaderType == HeaderType.RegularHeader) { ThrowHelper.ThrowStreamError_AfterRegularHeader(streamId, name); } var pseudoHeader = PseudoHeaderName.GetPseudoHeader(name); if (pseudoHeader is null) { ThrowHelper.ThrowStreamError_InvalidPseudoHeader(streamId, name); } HeaderType currentHeaderType = pseudoHeader.IsRequestOnly ? HeaderType.RequestPseudoHeader : HeaderType.ResponsePseudoHeader; if (previousHeaderType.HasValue && currentHeaderType != previousHeaderType.Value) { ThrowHelper.ThrowStreamError_MixOfRequest(streamId); } return(currentHeaderType); } return(HeaderType.RegularHeader); }
public void TranslateHeaders(IEnumerable <HeaderEntry <ICharSequence, ICharSequence> > inputHeaders) { // lazily created as needed StringBuilder cookies = null; foreach (var entry in inputHeaders) { var name = entry.Key; var value = entry.Value; if (_translations.TryGet(name, out var translatedName)) { _ = _output.Add(translatedName, AsciiString.Of(value)); } else if (!PseudoHeaderName.IsPseudoHeader(name)) { // https://tools.ietf.org/html/rfc7540#section-8.1.2.3 // All headers that start with ':' are only valid in HTTP/2 context if (0u >= (uint)name.Count || name[0] == ':') { StringBuilderManager.Free(cookies); ThrowHelper.ThrowStreamError_InvalidHttp2HeaderEncounteredInTranslationToHttp1(_streamId, name); } var cookie = HttpHeaderNames.Cookie; if (cookie.Equals(name)) { // combine the cookie values into 1 header entry. // https://tools.ietf.org/html/rfc7540#section-8.1.2.5 if (cookies is null) { cookies = StringBuilderManager.Allocate(); } else if ((uint)cookies.Length > 0u) { _ = cookies.Append("; "); } _ = cookies.Append(value.ToString()); } else { _ = _output.Add(AsciiString.Of(name), value); } } } if (cookies is object) { _ = _output.Add(HttpHeaderNames.Cookie, StringBuilderManager.ReturnAndFree(cookies)); } }