Skip to content

Commit

Permalink
Enable Form and Query access off of requests (#451)
Browse files Browse the repository at this point in the history
  • Loading branch information
twsouthwick authored Mar 22, 2022
1 parent 98f1924 commit b890e00
Show file tree
Hide file tree
Showing 14 changed files with 630 additions and 303 deletions.
14 changes: 8 additions & 6 deletions src/SystemWebAdapters/src/HttpRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ public class HttpRequest

private RequestHeaders? _typedHeaders;
private string[]? _userLanguages;
private StringValuesNameValueCollection? _headers;
private ServerVariablesNameValueCollection? _serverVariables;
private NameValueCollection? _headers;
private NameValueCollection? _serverVariables;
private NameValueCollection? _form;
private NameValueCollection? _query;

public HttpRequest(HttpRequestCore request)
{
Expand All @@ -34,7 +36,7 @@ public HttpRequest(HttpRequestCore request)

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

public NameValueCollection Headers => _headers ??= new(_request.Headers);
public NameValueCollection Headers => _headers ??= _request.Headers.ToNameValueCollection();

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

Expand Down Expand Up @@ -85,7 +87,7 @@ public string[] UserLanguages

public string RequestType => HttpMethod;

public NameValueCollection Form => throw new NotImplementedException();
public NameValueCollection Form => _form ??= _request.Form.ToNameValueCollection();

public HttpCookieCollection Cookies => throw new NotImplementedException();

Expand All @@ -109,7 +111,7 @@ public NameValueCollection ServerVariables
{
if (_request.HttpContext.Features.Get<IServerVariablesFeature>() is IServerVariablesFeature feature)
{
_serverVariables = new(feature);
_serverVariables = feature.ToNameValueCollection();
}
else
{
Expand All @@ -123,7 +125,7 @@ public NameValueCollection ServerVariables

public bool IsSecureConnection => _request.IsHttps;

public NameValueCollection QueryString => throw new NotImplementedException();
public NameValueCollection QueryString => _query ??= _request.Query.ToNameValueCollection();

public bool IsLocal
{
Expand Down
15 changes: 2 additions & 13 deletions src/SystemWebAdapters/src/HttpResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,8 @@ public string StatusDescription
set => throw new NotImplementedException();
}

public NameValueCollection Headers
{
get
{
if (_headers is null)
{
_headers = new StringValuesNameValueCollection(_response.Headers);
}

return _headers;
}
}

public NameValueCollection Headers => _headers ??= _response.Headers.ToNameValueCollection();

public bool TrySkipIisCustomErrors
{
get => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;

namespace System.Web.Internal;

internal class FormCollectionReadOnlyDictionary : IReadOnlyDictionary<string, StringValues>
{
private readonly IFormCollection _form;

public FormCollectionReadOnlyDictionary(IFormCollection form)
{
_form = form;
}

public StringValues this[string key] => _form[key];

public IEnumerable<string> Keys => _form.Keys;

public IEnumerable<StringValues> Values
{
get
{
foreach (var item in _form)
{
yield return item.Value;
}
}
}

public int Count => _form.Count;

public bool ContainsKey(string key) => _form.ContainsKey(key);

public IEnumerator<KeyValuePair<string, StringValues>> GetEnumerator() => _form.GetEnumerator();

public bool TryGetValue(string key, [MaybeNullWhen(false)] out StringValues value) => _form.TryGetValue(key, out value);

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Primitives;

namespace System.Web.Internal;

internal static class NameValueCollectionExtensions
{
public static NameValueCollection ToNameValueCollection(this IQueryCollection query)
{
if (query.Count == 0)
{
return StringValuesReadOnlyDictionaryNameValueCollection.Empty;
}

return new StringValuesReadOnlyDictionaryNameValueCollection(new QueryCollectionReadOnlyDictionary(query));
}

public static NameValueCollection ToNameValueCollection(this IFormCollection form)
{
if (form.Count == 0)
{
return StringValuesReadOnlyDictionaryNameValueCollection.Empty;
}

return new StringValuesReadOnlyDictionaryNameValueCollection(new FormCollectionReadOnlyDictionary(form));
}

public static NameValueCollection ToNameValueCollection(this IHeaderDictionary headers) => new StringValuesDictionaryNameValueCollection(headers);

public static NameValueCollection ToNameValueCollection(this IServerVariablesFeature serverVariables) => new ServerVariablesNameValueCollection(serverVariables);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;

namespace System.Web.Internal;

internal class QueryCollectionReadOnlyDictionary : IReadOnlyDictionary<string, StringValues>
{
private readonly IQueryCollection _query;

public QueryCollectionReadOnlyDictionary(IQueryCollection query)
{
_query = query;
}

public StringValues this[string key] => _query[key];

public IEnumerable<string> Keys => _query.Keys;

public IEnumerable<StringValues> Values
{
get
{
foreach (var item in _query)
{
yield return item.Value;
}
}
}

public int Count => _query.Count;

public bool ContainsKey(string key) => _query.ContainsKey(key);

public IEnumerator<KeyValuePair<string, StringValues>> GetEnumerator() => _query.GetEnumerator();

public bool TryGetValue(string key, [MaybeNullWhen(false)] out StringValues value) => _query.TryGetValue(key, out value);

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using System.Collections;
using System.Collections;
using System.Collections.Specialized;
using System.Runtime.Serialization;
using Microsoft.AspNetCore.Http.Features;

namespace System.Web.Internal
{
internal class ServerVariablesNameValueCollection : NameValueCollection
internal class ServerVariablesNameValueCollection : WrappingNameValueCollection
{
private const string EnumerationErrorMessage = "ASP.NET Core doesn't support enumerating server variables.";
private const string IndexErrorMessage = "ASP.NET Core doesn't support accessing server variables by index.";
private const string SerializationErrorMessage = "ASP.NET Core doesn't suppor serialization of server variables.";

private readonly IServerVariablesFeature _serverVariables;
Expand All @@ -33,14 +32,6 @@ public override void Add(string? name, string? value)
_serverVariables[name] = value;
}

public override KeysCollection Keys => throw new PlatformNotSupportedException("KeysCollection is not supported as Get(int) is not available.");

public override string? Get(int index) => throw new PlatformNotSupportedException(IndexErrorMessage);

public override string? GetKey(int index) => throw new PlatformNotSupportedException(IndexErrorMessage);

public override string[]? GetValues(int index) => throw new PlatformNotSupportedException(IndexErrorMessage);

public override string[]? GetValues(string? name)
{
if (name is not null && _serverVariables[name] is string result)
Expand Down Expand Up @@ -87,6 +78,6 @@ public override void Set(string? name, string? value)

public override void GetObjectData(SerializationInfo info, StreamingContext context) => throw new PlatformNotSupportedException(SerializationErrorMessage);

public override void OnDeserialization(object? sender)=> throw new PlatformNotSupportedException(SerializationErrorMessage);
public override void OnDeserialization(object? sender) => throw new PlatformNotSupportedException(SerializationErrorMessage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Primitives;

namespace System.Web.Internal
{
internal class StringValuesDictionaryNameValueCollection : WrappingNameValueCollection
{
private readonly IDictionary<string, StringValues> _values;

public StringValuesDictionaryNameValueCollection(IDictionary<string, StringValues> headers)
{
_values = headers;
}

public override string?[] AllKeys => _values.Keys.ToArray();

public override int Count => _values.Count;

public override void Add(string? name, string? value)
{
if (name is null)
{
return;
}

if (_values.TryGetValue(name, out var existing))
{
_values[name] = StringValues.Concat(existing, value);
}
else
{
_values.Add(name, value);
}
}

public override string[]? GetValues(string? name)
=> name is not null && _values.TryGetValue(name, out var values) ? values : default;

public override void Remove(string? name)
{
if (name is not null)
{
_values.Remove(name);
}
}

public override void Set(string? name, string? value)
{
if (name is null)
{
return;
}

_values[name] = value;
}

public override string? Get(string? name)
=> name is not null && _values.TryGetValue(name, out var values) ? values : default;

public override void Clear() => _values.Clear();

public override IEnumerator GetEnumerator() => _values.Keys.GetEnumerator();
}
}
Loading

0 comments on commit b890e00

Please sign in to comment.