287 lines
6.7 KiB
C#
287 lines
6.7 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNet.Http;
|
|
using Microsoft.AspNet.Http.Features;
|
|
using Microsoft.Extensions.Primitives;
|
|
|
|
namespace Microsoft.AspNet.Server.Kestrel.Http
|
|
{
|
|
public partial class Frame : IFeatureCollection, IHttpRequestFeature, IHttpResponseFeature, IHttpUpgradeFeature
|
|
{
|
|
// NOTE: When feature interfaces are added to or removed from this Frame class implementation,
|
|
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
|
// See also: tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode/FrameFeatureCollection.cs
|
|
|
|
private string _scheme;
|
|
private string _pathBase;
|
|
private int _featureRevision;
|
|
|
|
private List<KeyValuePair<Type, object>> MaybeExtra;
|
|
|
|
public void ResetFeatureCollection()
|
|
{
|
|
FastReset();
|
|
MaybeExtra?.Clear();
|
|
_featureRevision++;
|
|
}
|
|
|
|
private object ExtraFeatureGet(Type key)
|
|
{
|
|
if (MaybeExtra == null)
|
|
{
|
|
return null;
|
|
}
|
|
for (var i = 0; i < MaybeExtra.Count; i++)
|
|
{
|
|
var kv = MaybeExtra[i];
|
|
if (kv.Key == key)
|
|
{
|
|
return kv.Value;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void ExtraFeatureSet(Type key, object value)
|
|
{
|
|
if (MaybeExtra == null)
|
|
{
|
|
MaybeExtra = new List<KeyValuePair<Type, object>>(2);
|
|
}
|
|
|
|
for (var i = 0; i < MaybeExtra.Count; i++)
|
|
{
|
|
if (MaybeExtra[i].Key == key)
|
|
{
|
|
MaybeExtra[i] = new KeyValuePair<Type, object>(key, value);
|
|
return;
|
|
}
|
|
}
|
|
MaybeExtra.Add(new KeyValuePair<Type, object>(key, value));
|
|
}
|
|
|
|
|
|
string IHttpRequestFeature.Protocol
|
|
{
|
|
get
|
|
{
|
|
return HttpVersion;
|
|
}
|
|
|
|
set
|
|
{
|
|
HttpVersion = value;
|
|
}
|
|
}
|
|
|
|
string IHttpRequestFeature.Scheme
|
|
{
|
|
get
|
|
{
|
|
return _scheme ?? "http";
|
|
}
|
|
|
|
set
|
|
{
|
|
_scheme = value;
|
|
}
|
|
}
|
|
|
|
string IHttpRequestFeature.Method
|
|
{
|
|
get
|
|
{
|
|
return Method;
|
|
}
|
|
|
|
set
|
|
{
|
|
Method = value;
|
|
}
|
|
}
|
|
|
|
string IHttpRequestFeature.PathBase
|
|
{
|
|
get
|
|
{
|
|
return _pathBase ?? "";
|
|
}
|
|
|
|
set
|
|
{
|
|
_pathBase = value;
|
|
}
|
|
}
|
|
|
|
string IHttpRequestFeature.Path
|
|
{
|
|
get
|
|
{
|
|
return Path;
|
|
}
|
|
|
|
set
|
|
{
|
|
Path = value;
|
|
}
|
|
}
|
|
|
|
string IHttpRequestFeature.QueryString
|
|
{
|
|
get
|
|
{
|
|
return QueryString;
|
|
}
|
|
|
|
set
|
|
{
|
|
QueryString = value;
|
|
}
|
|
}
|
|
|
|
IHeaderDictionary IHttpRequestFeature.Headers
|
|
{
|
|
get
|
|
{
|
|
return RequestHeaders;
|
|
}
|
|
|
|
set
|
|
{
|
|
RequestHeaders = value;
|
|
}
|
|
}
|
|
|
|
Stream IHttpRequestFeature.Body
|
|
{
|
|
get
|
|
{
|
|
return RequestBody;
|
|
}
|
|
|
|
set
|
|
{
|
|
RequestBody = value;
|
|
}
|
|
}
|
|
|
|
int IHttpResponseFeature.StatusCode
|
|
{
|
|
get
|
|
{
|
|
return StatusCode;
|
|
}
|
|
|
|
set
|
|
{
|
|
StatusCode = value;
|
|
}
|
|
}
|
|
|
|
string IHttpResponseFeature.ReasonPhrase
|
|
{
|
|
get
|
|
{
|
|
return ReasonPhrase;
|
|
}
|
|
|
|
set
|
|
{
|
|
ReasonPhrase = value;
|
|
}
|
|
}
|
|
|
|
IHeaderDictionary IHttpResponseFeature.Headers
|
|
{
|
|
get
|
|
{
|
|
return ResponseHeaders;
|
|
}
|
|
|
|
set
|
|
{
|
|
ResponseHeaders = value;
|
|
}
|
|
}
|
|
|
|
Stream IHttpResponseFeature.Body
|
|
{
|
|
get
|
|
{
|
|
return ResponseBody;
|
|
}
|
|
|
|
set
|
|
{
|
|
ResponseBody = value;
|
|
}
|
|
}
|
|
|
|
bool IHttpResponseFeature.HasStarted
|
|
{
|
|
get { return HasResponseStarted; }
|
|
}
|
|
|
|
bool IHttpUpgradeFeature.IsUpgradableRequest
|
|
{
|
|
get
|
|
{
|
|
StringValues values;
|
|
if (RequestHeaders.TryGetValue("Connection", out values))
|
|
{
|
|
return values.Any(value => value.IndexOf("upgrade", StringComparison.OrdinalIgnoreCase) != -1);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool IFeatureCollection.IsReadOnly => false;
|
|
|
|
int IFeatureCollection.Revision => _featureRevision;
|
|
|
|
object IFeatureCollection.this[Type key]
|
|
{
|
|
get { return FastFeatureGet(key); }
|
|
set { FastFeatureSet(key, value); }
|
|
}
|
|
|
|
void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state)
|
|
{
|
|
OnStarting(callback, state);
|
|
}
|
|
|
|
void IHttpResponseFeature.OnCompleted(Func<object, Task> callback, object state)
|
|
{
|
|
OnCompleted(callback, state);
|
|
}
|
|
|
|
Task<Stream> IHttpUpgradeFeature.UpgradeAsync()
|
|
{
|
|
StatusCode = 101;
|
|
ReasonPhrase = "Switching Protocols";
|
|
ResponseHeaders["Connection"] = "Upgrade";
|
|
if (!ResponseHeaders.ContainsKey("Upgrade"))
|
|
{
|
|
StringValues values;
|
|
if (RequestHeaders.TryGetValue("Upgrade", out values))
|
|
{
|
|
ResponseHeaders["Upgrade"] = values;
|
|
}
|
|
}
|
|
ProduceStartAndFireOnStarting(immediate: true).GetAwaiter().GetResult();
|
|
return Task.FromResult(DuplexStream);
|
|
}
|
|
|
|
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
|
|
}
|
|
}
|