Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement some HttpRequest APIs against core #435

Merged
merged 12 commits into from
Feb 16, 2022
133 changes: 112 additions & 21 deletions src/SystemWebAdapters/src/HttpRequest.cs
Original file line number Diff line number Diff line change
@@ -1,89 +1,180 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
using System.Security.Principal;
using System.Text;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Headers;
using Microsoft.Net.Http.Headers;

namespace System.Web
{
public class HttpRequest
{
private readonly HttpRequestCore _request;

private RequestHeaders? _typedHeaders;
private string[]? _userLanguages;

public HttpRequest(HttpRequestCore request)
{
_request = request;
}

public string Path => throw new NotImplementedException();
public string? Path => _request.Path.Value;

public NameValueCollection Headers => throw new NotImplementedException();

public Uri Url => throw new NotImplementedException();
public Uri Url => new(_request.GetEncodedUrl());

// TODO: https://github.com/aspnet/AspLabs/pull/435#discussion_r807128348
public string RawUrl => throw new NotImplementedException();

public string HttpMethod => throw new NotImplementedException();
public string HttpMethod => _request.Method;

public string UserHostAddress => throw new NotImplementedException();
public string? UserHostAddress => _request.HttpContext.Connection.RemoteIpAddress?.ToString();

public string[] UserLanguages => throw new NotImplementedException();
public string[] UserLanguages
{
get
{
if (_userLanguages is null)
{
var languages = TypedHeaders.AcceptLanguage;
var length = languages.Count;

if (length == 0)
{
_userLanguages = Array.Empty<string>();
}
else
{
var qualityArray = ArrayPool<StringWithQualityHeaderValue>.Shared.Rent(length);
var userLanguages = new string[length];

languages.CopyTo(qualityArray, 0);
Array.Sort(qualityArray, 0, length, StringWithQualityHeaderValueComparer.Instance);

for (var i = 0; i < length; i++)
{
userLanguages[i] = qualityArray[i].Value.Value;
}

ArrayPool<StringWithQualityHeaderValue>.Shared.Return(qualityArray);

_userLanguages = userLanguages;
}
}

return _userLanguages;
}
}

public string UserAgent => _request.Headers["User-Agent"];
public string UserAgent => _request.Headers[HeaderNames.UserAgent];

public string RequestType => HttpMethod;

public NameValueCollection Form => throw new NotImplementedException();

public HttpCookieCollection Cookies => throw new NotImplementedException();

public int ContentLength => throw new NotImplementedException();
public int ContentLength => (int)(_request.ContentLength ?? 0);

public string ContentType
public string? ContentType
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
get => _request.ContentType;
set => _request.ContentType = value;
}

public Stream InputStream => throw new NotImplementedException();

public NameValueCollection ServerVariables => throw new NotImplementedException();

public bool IsSecureConnection => throw new NotImplementedException();
public bool IsSecureConnection => _request.IsHttps;

public NameValueCollection QueryString => throw new NotImplementedException();

public bool IsLocal => throw new NotImplementedException();
public bool IsLocal
{
get
{
var connectionInfo = _request.HttpContext.Connection;

// If unknown, assume not local
if (connectionInfo.RemoteIpAddress is null)
{
return false;
}

// Check if localhost
if (IPAddress.IsLoopback(connectionInfo.RemoteIpAddress))
{
return true;
}

return connectionInfo.RemoteIpAddress.Equals(connectionInfo.LocalIpAddress);
}
}

public string AppRelativeCurrentExecutionFilePath => throw new NotImplementedException();
public string AppRelativeCurrentExecutionFilePath => $"~{_request.Path.Value}";

public string ApplicationPath => throw new NotImplementedException();
public string? ApplicationPath => _request.PathBase.Value;

public Uri UrlReferrer => throw new NotImplementedException();
public Uri? UrlReferrer => TypedHeaders.Referer;

public int TotalBytes => throw new NotImplementedException();
// TODO: Since System.Web buffered by default, TotalBytes probably also worked for Chunked requests. We'll want to revisit this when we look at the request body buffering.
public int TotalBytes => (int)_request.ContentLength.GetValueOrDefault();

public bool IsAuthenticated => throw new NotImplementedException();
public bool IsAuthenticated => LogonUserIdentity?.IsAuthenticated ?? false;

public IIdentity LogonUserIdentity => throw new NotImplementedException();
public IIdentity? LogonUserIdentity => _request.HttpContext.User.Identity;

public Encoding ContentEncoding => throw new NotImplementedException();
public Encoding? ContentEncoding => TypedHeaders.ContentType?.Encoding;

public string UserHostName => throw new NotImplementedException();
public string? UserHostName => _request.HttpContext.Connection.RemoteIpAddress?.ToString();

public HttpBrowserCapabilities Browser => throw new NotImplementedException();

public byte[] BinaryRead(int count) => throw new NotImplementedException();

public void Abort() => throw new NotImplementedException();
public void Abort() => _request.HttpContext.Abort();

private RequestHeaders TypedHeaders
{
get
{
if (_typedHeaders is null)
{
_typedHeaders = new(_request.Headers);
}

return _typedHeaders;
}
}

[return: NotNullIfNotNull("request")]
public static implicit operator HttpRequest?(HttpRequestCore? request) => request.GetAdapter();

[return: NotNullIfNotNull("request")]
public static implicit operator HttpRequestCore?(HttpRequest? request) => request?._request;

private class StringWithQualityHeaderValueComparer : IComparer<StringWithQualityHeaderValue>
{
public static StringWithQualityHeaderValueComparer Instance { get; } = new();

public int Compare(StringWithQualityHeaderValue? x, StringWithQualityHeaderValue? y)
{
var xValue = x?.Quality ?? 1;
var yValue = y?.Quality ?? 1;

return yValue.CompareTo(xValue);
}
}
}
}
14 changes: 7 additions & 7 deletions src/SystemWebAdapters/src/HttpRequestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace System.Web
{
public abstract class HttpRequestBase
{
public virtual string Path => throw new NotImplementedException();
public virtual string? Path => throw new NotImplementedException();

public virtual NameValueCollection Headers => throw new NotImplementedException();

Expand All @@ -20,7 +20,7 @@ public abstract class HttpRequestBase

public virtual string HttpMethod => throw new NotImplementedException();

public virtual string UserHostAddress => throw new NotImplementedException();
public virtual string? UserHostAddress => throw new NotImplementedException();

public virtual string[] UserLanguages => throw new NotImplementedException();

Expand All @@ -32,7 +32,7 @@ public abstract class HttpRequestBase

public virtual int ContentLength => throw new NotImplementedException();

public virtual string ContentType
public virtual string? ContentType
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
Expand All @@ -52,17 +52,17 @@ public virtual string ContentType

public string ApplicationPath => throw new NotImplementedException();

public virtual Uri UrlReferrer => throw new NotImplementedException();
public virtual Uri? UrlReferrer => throw new NotImplementedException();

public virtual int TotalBytes => throw new NotImplementedException();

public virtual bool IsAuthenticated => throw new NotImplementedException();

public virtual IIdentity LogonUserIdentity => throw new NotImplementedException();
public virtual IIdentity? LogonUserIdentity => throw new NotImplementedException();

public virtual Encoding ContentEncoding => throw new NotImplementedException();
public virtual Encoding? ContentEncoding => throw new NotImplementedException();

public virtual string UserHostName => throw new NotImplementedException();
public virtual string? UserHostName => throw new NotImplementedException();

public HttpBrowserCapabilities Browser => throw new NotImplementedException();

Expand Down
14 changes: 7 additions & 7 deletions src/SystemWebAdapters/src/HttpRequestWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ public HttpRequestWrapper(HttpRequest request)

public override byte[] BinaryRead(int count) => _request.BinaryRead(count);

public override Encoding ContentEncoding => _request.ContentEncoding;
public override Encoding? ContentEncoding => _request.ContentEncoding;

public override int ContentLength => _request.ContentLength;

public override string ContentType
public override string? ContentType
{
get => _request.ContentType;
set => _request.ContentType = value;
Expand All @@ -43,9 +43,9 @@ public override string ContentType

public override bool IsLocal => _request.IsLocal;

public override IIdentity LogonUserIdentity => _request.LogonUserIdentity;
public override IIdentity? LogonUserIdentity => _request.LogonUserIdentity;

public override string Path => _request.Path;
public override string? Path => _request.Path;

public override NameValueCollection QueryString => _request.QueryString;

Expand All @@ -57,13 +57,13 @@ public override string ContentType

public override Uri Url => _request.Url;

public override Uri UrlReferrer => _request.UrlReferrer;
public override Uri? UrlReferrer => _request.UrlReferrer;

public override string UserAgent => _request.UserAgent;

public override string UserHostAddress => _request.UserHostAddress;
public override string? UserHostAddress => _request.UserHostAddress;

public override string UserHostName => _request.UserHostName;
public override string? UserHostName => _request.UserHostName;

public override string[] UserLanguages => _request.UserLanguages;
}
Expand Down
11 changes: 7 additions & 4 deletions src/SystemWebAdapters/src/System.Web.Adapters.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;netstandard2.0;net472</TargetFrameworks>
<TargetFrameworks>net6.0;netcoreapp3.1;netstandard2.0;net472</TargetFrameworks>
<HasImplementation>false</HasImplementation>
<HasImplementation Condition=" '$(TargetFramework)' == 'net6.0' OR '$(TargetFramework)' == 'netcoreapp3.1' ">true</HasImplementation>
<LangVersion>10</LangVersion>
<IsPackable>true</IsPackable>
<Nullable>enable</Nullable>
<RootNamespace>System.Web</RootNamespace>
</PropertyGroup>

<ItemGroup>
Expand All @@ -16,7 +19,7 @@
<Compile Include="NetStandard/**" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<ItemGroup Condition="$(HasImplementation)">
<Compile Remove="Framework/**" />
<Compile Remove="NetStandard/**" />

Expand All @@ -33,6 +36,6 @@
<Reference Include="System.Web" />
</ItemGroup>

<Import Condition=" '$(TargetFramework)' == 'netcoreapp3.1' " Project="GenerateApis.targets" />
<Import Condition="$(HasImplementation)" Project="GenerateApis.targets" />

</Project>
1 change: 1 addition & 0 deletions src/SystemWebAdapters/src/SystemWebAdaptersExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace System.Web
Expand Down
Loading