mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-23 22:25:09 -04:00
imported signalr 1.1.3 into NzbDrone.
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.SignalR.Hosting;
|
||||
using Microsoft.AspNet.SignalR.Owin.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin
|
||||
{
|
||||
public class CallHandler
|
||||
{
|
||||
private readonly ConnectionConfiguration _configuration;
|
||||
private readonly PersistentConnection _connection;
|
||||
|
||||
public CallHandler(ConnectionConfiguration configuration, PersistentConnection connection)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_connection = connection;
|
||||
}
|
||||
|
||||
public Task Invoke(IDictionary<string, object> environment)
|
||||
{
|
||||
var serverRequest = new ServerRequest(environment);
|
||||
var serverResponse = new ServerResponse(environment);
|
||||
var hostContext = new HostContext(serverRequest, serverResponse);
|
||||
|
||||
string origin = serverRequest.RequestHeaders.GetHeader("Origin");
|
||||
|
||||
if (_configuration.EnableCrossDomain)
|
||||
{
|
||||
// Add CORS response headers support
|
||||
if (!String.IsNullOrEmpty(origin))
|
||||
{
|
||||
serverResponse.ResponseHeaders.SetHeader("Access-Control-Allow-Origin", origin);
|
||||
serverResponse.ResponseHeaders.SetHeader("Access-Control-Allow-Credentials", "true");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string callback = serverRequest.QueryString["callback"];
|
||||
|
||||
// If it's a JSONP request and we're not allowing cross domain requests then block it
|
||||
// If there's an origin header and it's not a same origin request then block it.
|
||||
|
||||
if (!String.IsNullOrEmpty(callback) ||
|
||||
(!String.IsNullOrEmpty(origin) && !IsSameOrigin(serverRequest.Url, origin)))
|
||||
{
|
||||
return EndResponse(environment, 403, Resources.Forbidden_CrossDomainIsDisabled);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the nosniff header for all responses to prevent IE from trying to sniff mime type from contents
|
||||
serverResponse.ResponseHeaders.SetHeader("X-Content-Type-Options", "nosniff");
|
||||
|
||||
// REVIEW: Performance
|
||||
hostContext.Items[HostConstants.SupportsWebSockets] = environment.SupportsWebSockets();
|
||||
hostContext.Items[HostConstants.ShutdownToken] = environment.GetShutdownToken();
|
||||
hostContext.Items[HostConstants.DebugMode] = environment.GetIsDebugEnabled();
|
||||
|
||||
serverRequest.DisableRequestCompression();
|
||||
serverResponse.DisableResponseBuffering();
|
||||
|
||||
_connection.Initialize(_configuration.Resolver, hostContext);
|
||||
|
||||
if (!_connection.Authorize(serverRequest))
|
||||
{
|
||||
// If we failed to authorize the request then return a 403 since the request
|
||||
// can't do anything
|
||||
return EndResponse(environment, 403, "Forbidden");
|
||||
}
|
||||
else
|
||||
{
|
||||
return _connection.ProcessRequest(hostContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static Task EndResponse(IDictionary<string, object> environment, int statusCode, string reason)
|
||||
{
|
||||
environment[OwinConstants.ResponseStatusCode] = statusCode;
|
||||
environment[OwinConstants.ResponseReasonPhrase] = reason;
|
||||
|
||||
return TaskAsyncHelper.Empty;
|
||||
}
|
||||
|
||||
private static bool IsSameOrigin(Uri requestUri, string origin)
|
||||
{
|
||||
Uri originUri;
|
||||
if (!Uri.TryCreate(origin.Trim(), UriKind.Absolute, out originUri))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return (requestUri.Scheme == originUri.Scheme) &&
|
||||
(requestUri.Host == originUri.Host) &&
|
||||
(requestUri.Port == originUri.Port);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.SignalR.Hubs;
|
||||
using Microsoft.AspNet.SignalR.Owin.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin.Handlers
|
||||
{
|
||||
using AppFunc = Func<IDictionary<string, object>, Task>;
|
||||
|
||||
public class HubDispatcherHandler
|
||||
{
|
||||
private readonly AppFunc _next;
|
||||
private readonly string _path;
|
||||
private readonly HubConfiguration _configuration;
|
||||
|
||||
public HubDispatcherHandler(AppFunc next, string path, HubConfiguration configuration)
|
||||
{
|
||||
_next = next;
|
||||
_path = path;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public Task Invoke(IDictionary<string, object> environment)
|
||||
{
|
||||
var path = environment.Get<string>(OwinConstants.RequestPath);
|
||||
if (path == null || !PrefixMatcher.IsMatch(_path, path))
|
||||
{
|
||||
return _next(environment);
|
||||
}
|
||||
|
||||
var dispatcher = new HubDispatcher(_configuration);
|
||||
|
||||
var handler = new CallHandler(_configuration, dispatcher);
|
||||
return handler.Invoke(environment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.SignalR.Hosting;
|
||||
using Microsoft.AspNet.SignalR.Owin.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin.Handlers
|
||||
{
|
||||
using AppFunc = Func<IDictionary<string, object>, Task>;
|
||||
|
||||
public class PersistentConnectionHandler
|
||||
{
|
||||
private readonly AppFunc _next;
|
||||
private readonly string _path;
|
||||
private readonly Type _connectionType;
|
||||
private readonly ConnectionConfiguration _configuration;
|
||||
|
||||
public PersistentConnectionHandler(AppFunc next, string path, Type connectionType, ConnectionConfiguration configuration)
|
||||
{
|
||||
_next = next;
|
||||
_path = path;
|
||||
_connectionType = connectionType;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public Task Invoke(IDictionary<string, object> environment)
|
||||
{
|
||||
var path = environment.Get<string>(OwinConstants.RequestPath);
|
||||
if (path == null || !PrefixMatcher.IsMatch(_path, path))
|
||||
{
|
||||
return _next(environment);
|
||||
}
|
||||
|
||||
var connectionFactory = new PersistentConnectionFactory(_configuration.Resolver);
|
||||
var connection = connectionFactory.CreateInstance(_connectionType);
|
||||
|
||||
var handler = new CallHandler(_configuration, connection);
|
||||
return handler.Invoke(environment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper methods for creating and consuming CallParameters.Headers and ResultParameters.Headers.
|
||||
/// </summary>
|
||||
internal static class Headers
|
||||
{
|
||||
public static IDictionary<string, string[]> SetHeader(this IDictionary<string, string[]> headers,
|
||||
string name, string value)
|
||||
{
|
||||
headers[name] = new[] { value };
|
||||
return headers;
|
||||
}
|
||||
|
||||
public static string[] GetHeaders(this IDictionary<string, string[]> headers,
|
||||
string name)
|
||||
{
|
||||
string[] value;
|
||||
return headers != null && headers.TryGetValue(name, out value) ? value : null;
|
||||
}
|
||||
|
||||
public static string GetHeader(this IDictionary<string, string[]> headers,
|
||||
string name)
|
||||
{
|
||||
var values = GetHeaders(headers, name);
|
||||
if (values == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (values.Length)
|
||||
{
|
||||
case 0:
|
||||
return String.Empty;
|
||||
case 1:
|
||||
return values[0];
|
||||
default:
|
||||
return String.Join(",", values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin
|
||||
{
|
||||
internal static class OwinConstants
|
||||
{
|
||||
public const string Version = "owin.Version";
|
||||
|
||||
public const string RequestBody = "owin.RequestBody";
|
||||
public const string RequestHeaders = "owin.RequestHeaders";
|
||||
public const string RequestScheme = "owin.RequestScheme";
|
||||
public const string RequestMethod = "owin.RequestMethod";
|
||||
public const string RequestPathBase = "owin.RequestPathBase";
|
||||
public const string RequestPath = "owin.RequestPath";
|
||||
public const string RequestQueryString = "owin.RequestQueryString";
|
||||
public const string RequestProtocol = "owin.RequestProtocol";
|
||||
|
||||
public const string CallCancelled = "owin.CallCancelled";
|
||||
|
||||
public const string ResponseStatusCode = "owin.ResponseStatusCode";
|
||||
public const string ResponseReasonPhrase = "owin.ResponseReasonPhrase";
|
||||
public const string ResponseHeaders = "owin.ResponseHeaders";
|
||||
public const string ResponseBody = "owin.ResponseBody";
|
||||
|
||||
public const string TraceOutput = "host.TraceOutput";
|
||||
|
||||
public const string User = "server.User";
|
||||
public const string RemoteIpAddress = "server.RemoteIpAddress";
|
||||
public const string RemotePort = "server.RemotePort";
|
||||
public const string LocalIpAddress = "server.LocalIpAddress";
|
||||
public const string LocalPort = "server.LocalPort";
|
||||
|
||||
public const string DisableRequestCompression = "systemweb.DisableResponseCompression";
|
||||
public const string DisableRequestBuffering = "server.DisableRequestBuffering";
|
||||
public const string DisableResponseBuffering = "server.DisableResponseBuffering";
|
||||
|
||||
public const string ServerCapabilities = "server.Capabilities";
|
||||
public const string WebSocketVersion = "websocket.Version";
|
||||
public const string WebSocketAccept = "websocket.Accept";
|
||||
|
||||
public const string HostOnAppDisposing = "host.OnAppDisposing";
|
||||
public const string HostAppNameKey = "host.AppName";
|
||||
public const string HostAppModeKey = "host.AppMode";
|
||||
public const string AppModeDevelopment = "development";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin
|
||||
{
|
||||
internal static class OwinEnvironmentExtensions
|
||||
{
|
||||
internal static T Get<T>(this IDictionary<string, object> environment, string key)
|
||||
{
|
||||
object value;
|
||||
return environment.TryGetValue(key, out value) ? (T)value : default(T);
|
||||
}
|
||||
|
||||
internal static CancellationToken GetShutdownToken(this IDictionary<string, object> env)
|
||||
{
|
||||
object value;
|
||||
return env.TryGetValue(OwinConstants.HostOnAppDisposing, out value)
|
||||
&& value is CancellationToken
|
||||
? (CancellationToken)value
|
||||
: default(CancellationToken);
|
||||
}
|
||||
|
||||
internal static string GetAppInstanceName(this IDictionary<string, object> environment)
|
||||
{
|
||||
object value;
|
||||
if (environment.TryGetValue(OwinConstants.HostAppNameKey, out value))
|
||||
{
|
||||
var stringVal = value as string;
|
||||
|
||||
if (!String.IsNullOrEmpty(stringVal))
|
||||
{
|
||||
return stringVal;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static bool SupportsWebSockets(this IDictionary<string, object> environment)
|
||||
{
|
||||
object value;
|
||||
if (environment.TryGetValue(OwinConstants.ServerCapabilities, out value))
|
||||
{
|
||||
var capabilities = value as IDictionary<string, object>;
|
||||
if (capabilities != null)
|
||||
{
|
||||
return capabilities.ContainsKey(OwinConstants.WebSocketVersion);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool GetIsDebugEnabled(this IDictionary<string, object> environment)
|
||||
{
|
||||
object value;
|
||||
if (environment.TryGetValue(OwinConstants.HostAppModeKey, out value))
|
||||
{
|
||||
var stringVal = value as string;
|
||||
return !String.IsNullOrWhiteSpace(stringVal) &&
|
||||
OwinConstants.AppModeDevelopment.Equals(stringVal, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNet.SignalR.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin.Infrastructure
|
||||
{
|
||||
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "It is instantiated in the static Parse method")]
|
||||
internal sealed class ParamDictionary
|
||||
{
|
||||
private static readonly char[] DefaultParamSeparators = new[] { '&', ';' };
|
||||
private static readonly char[] ParamKeyValueSeparator = new[] { '=' };
|
||||
private static readonly char[] LeadingWhitespaceChars = new[] { ' ' };
|
||||
|
||||
internal static IEnumerable<KeyValuePair<string, string>> ParseToEnumerable(string value, char[] delimiters = null)
|
||||
{
|
||||
value = value ?? String.Empty;
|
||||
delimiters = delimiters ?? DefaultParamSeparators;
|
||||
|
||||
var items = value.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
string[] pair = item.Split(ParamKeyValueSeparator, 2, StringSplitOptions.None);
|
||||
|
||||
string pairKey = UrlDecoder.UrlDecode(pair[0]).TrimStart(LeadingWhitespaceChars);
|
||||
string pairValue = pair.Length < 2 ? String.Empty : UrlDecoder.UrlDecode(pair[1]);
|
||||
|
||||
yield return new KeyValuePair<string, string>(pairKey, pairValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin.Infrastructure
|
||||
{
|
||||
internal static class PrefixMatcher
|
||||
{
|
||||
public static bool IsMatch(string pathBase, string path)
|
||||
{
|
||||
pathBase = EnsureStartsWithSlash(pathBase);
|
||||
path = EnsureStartsWithSlash(path);
|
||||
|
||||
var pathLength = path.Length;
|
||||
var pathBaseLength = pathBase.Length;
|
||||
|
||||
if (pathLength < pathBaseLength)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pathLength > pathBaseLength && path[pathBaseLength] != '/')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!path.StartsWith(pathBase, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string EnsureStartsWithSlash(string path)
|
||||
{
|
||||
if (path.Length == 0)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
if (path[0] == '/')
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
return '/' + path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Infrastructure
|
||||
{
|
||||
// Taken from System.Net.Http.Formatting.Internal.UrlDecoder.cs (http://aspnetwebstack.codeplex.com/)
|
||||
|
||||
/// <summary>
|
||||
/// Helpers for decoding URI query components.
|
||||
/// </summary>
|
||||
internal static class UrlDecoder
|
||||
{
|
||||
// The implementation below is ported from WebUtility for use in .Net 4
|
||||
|
||||
public static string UrlDecode(string str)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
return UrlDecodeInternal(str, Encoding.UTF8);
|
||||
}
|
||||
|
||||
#region UrlDecode implementation
|
||||
|
||||
private static string UrlDecodeInternal(string value, Encoding encoding)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int count = value.Length;
|
||||
var helper = new DecoderHelper(count, encoding);
|
||||
|
||||
// go through the string's chars collapsing %XX and %uXXXX and
|
||||
// appending each char as char, with exception of %XX constructs
|
||||
// that are appended as bytes
|
||||
|
||||
for (int pos = 0; pos < count; pos++)
|
||||
{
|
||||
char ch = value[pos];
|
||||
|
||||
if (ch == '+')
|
||||
{
|
||||
ch = ' ';
|
||||
}
|
||||
else if (ch == '%' && pos < count - 2)
|
||||
{
|
||||
int h1 = HexToInt(value[pos + 1]);
|
||||
int h2 = HexToInt(value[pos + 2]);
|
||||
|
||||
if (h1 >= 0 && h2 >= 0)
|
||||
{ // valid 2 hex chars
|
||||
byte b = (byte)((h1 << 4) | h2);
|
||||
pos += 2;
|
||||
|
||||
// don't add as char
|
||||
helper.AddByte(b);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ch & 0xFF80) == 0)
|
||||
helper.AddByte((byte)ch); // 7 bit have to go as bytes because of Unicode
|
||||
else
|
||||
helper.AddChar(ch);
|
||||
}
|
||||
|
||||
return helper.GetString();
|
||||
}
|
||||
|
||||
private static int HexToInt(char h)
|
||||
{
|
||||
return (h >= '0' && h <= '9') ? h - '0' :
|
||||
(h >= 'a' && h <= 'f') ? h - 'a' + 10 :
|
||||
(h >= 'A' && h <= 'F') ? h - 'A' + 10 :
|
||||
-1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DecoderHelper nested class
|
||||
|
||||
// Internal class to facilitate URL decoding -- keeps char buffer and byte buffer, allows appending of either chars or bytes
|
||||
private class DecoderHelper
|
||||
{
|
||||
private int _bufferSize;
|
||||
|
||||
// Accumulate characters in a special array
|
||||
private int _numChars;
|
||||
private char[] _charBuffer;
|
||||
|
||||
// Accumulate bytes for decoding into characters in a special array
|
||||
private int _numBytes;
|
||||
private byte[] _byteBuffer;
|
||||
|
||||
// Encoding to convert chars to bytes
|
||||
private Encoding _encoding;
|
||||
|
||||
private void FlushBytes()
|
||||
{
|
||||
if (_numBytes > 0)
|
||||
{
|
||||
_numChars += _encoding.GetChars(_byteBuffer, 0, _numBytes, _charBuffer, _numChars);
|
||||
_numBytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
internal DecoderHelper(int bufferSize, Encoding encoding)
|
||||
{
|
||||
_bufferSize = bufferSize;
|
||||
_encoding = encoding;
|
||||
|
||||
_charBuffer = new char[bufferSize];
|
||||
// byte buffer created on demand
|
||||
}
|
||||
|
||||
internal void AddChar(char ch)
|
||||
{
|
||||
if (_numBytes > 0)
|
||||
FlushBytes();
|
||||
|
||||
_charBuffer[_numChars++] = ch;
|
||||
}
|
||||
|
||||
internal void AddByte(byte b)
|
||||
{
|
||||
if (_byteBuffer == null)
|
||||
_byteBuffer = new byte[_bufferSize];
|
||||
|
||||
_byteBuffer[_numBytes++] = b;
|
||||
}
|
||||
|
||||
internal String GetString()
|
||||
{
|
||||
if (_numBytes > 0)
|
||||
FlushBytes();
|
||||
|
||||
if (_numChars > 0)
|
||||
return new String(_charBuffer, 0, _numChars);
|
||||
else
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{2B8C6DAD-4D85-41B1-83FD-248D9F347522}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Microsoft.AspNet.SignalR.Owin</RootNamespace>
|
||||
<AssemblyName>Microsoft.AspNet.SignalR.Owin</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
|
||||
<RestorePackages>true</RestorePackages>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<DocumentationFile>bin\Debug\Microsoft.AspNet.SignalR.Owin.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<DocumentationFile>bin\Release\Microsoft.AspNet.SignalR.Owin.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f585506a2da1fef4, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Common\CommonAssemblyInfo.cs">
|
||||
<Link>Properties\CommonAssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Common\CommonVersionInfo.cs">
|
||||
<Link>Properties\CommonVersionInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Microsoft.AspNet.SignalR.Core\TaskAsyncHelper.cs">
|
||||
<Link>Infrastructure\TaskAsyncHelper.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Infrastructure\Headers.cs" />
|
||||
<Compile Include="Infrastructure\OwinConstants.cs" />
|
||||
<Compile Include="Infrastructure\OwinEnvironmentExtensions.cs" />
|
||||
<Compile Include="Infrastructure\ParamDictionary.cs" />
|
||||
<Compile Include="Handlers\CallHandler.cs" />
|
||||
<Compile Include="Handlers\PersistentConnectionHandler.cs" />
|
||||
<Compile Include="Handlers\HubDispatcherHandler.cs" />
|
||||
<Compile Include="Infrastructure\PrefixMatcher.cs" />
|
||||
<Compile Include="Infrastructure\UrlDecoder.cs" />
|
||||
<Compile Include="RequestExtensions.cs" />
|
||||
<Compile Include="Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ServerRequest.Owin.cs" />
|
||||
<Compile Include="ServerRequest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ServerResponse.cs" />
|
||||
<Compile Include="OwinExtensions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNet.SignalR.Core\Microsoft.AspNet.SignalR.Core.csproj">
|
||||
<Project>{1B9A82C4-BCA1-4834-A33E-226F17BE070B}</Project>
|
||||
<Name>Microsoft.AspNet.SignalR.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="..\Common\Microsoft.AspNet.SignalR.targets" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="!HasTrailingSlash('$(SolutionDir)')" />
|
||||
<Import Project="$(SolutionDir).nuget\NuGet.targets" Condition="HasTrailingSlash('$(SolutionDir)')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CheckNamespace/@EntryIndexedValue">DO_NOT_SHOW</s:String></wpf:ResourceDictionary>
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Microsoft.AspNet.SignalR.Hosting;
|
||||
using Microsoft.AspNet.SignalR.Owin;
|
||||
using Microsoft.AspNet.SignalR.Owin.Handlers;
|
||||
|
||||
namespace Owin
|
||||
{
|
||||
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Owin", Justification = "The owin namespace is for consistentcy.")]
|
||||
public static class OwinExtensions
|
||||
{
|
||||
public static IAppBuilder MapHubs(this IAppBuilder builder)
|
||||
{
|
||||
return builder.MapHubs(new HubConfiguration());
|
||||
}
|
||||
|
||||
public static IAppBuilder MapHubs(this IAppBuilder builder, HubConfiguration configuration)
|
||||
{
|
||||
return builder.MapHubs("/signalr", configuration);
|
||||
}
|
||||
|
||||
public static IAppBuilder MapHubs(this IAppBuilder builder, string path, HubConfiguration configuration)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
throw new ArgumentNullException("configuration");
|
||||
}
|
||||
|
||||
return builder.UseType<HubDispatcherHandler>(path, configuration);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "The type parameter is syntactic sugar")]
|
||||
public static IAppBuilder MapConnection<T>(this IAppBuilder builder, string url) where T : PersistentConnection
|
||||
{
|
||||
return builder.MapConnection(url, typeof(T), new ConnectionConfiguration());
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "The type parameter is syntactic sugar")]
|
||||
public static IAppBuilder MapConnection<T>(this IAppBuilder builder, string url, ConnectionConfiguration configuration) where T : PersistentConnection
|
||||
{
|
||||
return builder.MapConnection(url, typeof(T), configuration);
|
||||
}
|
||||
|
||||
public static IAppBuilder MapConnection(this IAppBuilder builder, string url, Type connectionType, ConnectionConfiguration configuration)
|
||||
{
|
||||
if (configuration == null)
|
||||
{
|
||||
throw new ArgumentNullException("configuration");
|
||||
}
|
||||
|
||||
return builder.UseType<PersistentConnectionHandler>(url, connectionType, configuration);
|
||||
}
|
||||
|
||||
private static IAppBuilder UseType<T>(this IAppBuilder builder, params object[] args)
|
||||
{
|
||||
if (args.Length > 0)
|
||||
{
|
||||
var configuration = args[args.Length - 1] as ConnectionConfiguration;
|
||||
|
||||
if (configuration == null)
|
||||
{
|
||||
throw new ArgumentException(Resources.Error_NoConfiguration);
|
||||
}
|
||||
|
||||
var resolver = configuration.Resolver;
|
||||
|
||||
if (resolver == null)
|
||||
{
|
||||
throw new ArgumentException(Resources.Error_NoDepenendeyResolver);
|
||||
}
|
||||
|
||||
var env = builder.Properties;
|
||||
CancellationToken token = env.GetShutdownToken();
|
||||
string instanceName = env.GetAppInstanceName();
|
||||
|
||||
resolver.InitializeHost(instanceName, token);
|
||||
}
|
||||
|
||||
return builder.Use(typeof(T), args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyTitle("Microsoft.AspNet.SignalR.Owin")]
|
||||
[assembly: AssemblyDescription("Assembly containing default SignalR host.")]
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.SignalR.Owin;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR
|
||||
{
|
||||
public static class RequestExtensions
|
||||
{
|
||||
public static T GetOwinVariable<T>(this IRequest request, string key)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException("request");
|
||||
}
|
||||
|
||||
var env = request.Items.Get<IDictionary<string, object>>(ServerRequest.OwinEnvironmentKey);
|
||||
|
||||
return env == null ? default(T) : env.Get<T>(key);
|
||||
}
|
||||
|
||||
private static T Get<T>(this IDictionary<string, object> values, string key)
|
||||
{
|
||||
object value;
|
||||
return values.TryGetValue(key, out value) ? (T)value : default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18010
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.AspNet.SignalR.Owin.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to A configuration object must be specified..
|
||||
/// </summary>
|
||||
internal static string Error_NoConfiguration {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_NoConfiguration", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to A dependency resolver must be specified..
|
||||
/// </summary>
|
||||
internal static string Error_NoDepenendeyResolver {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_NoDepenendeyResolver", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Not a valid web socket request..
|
||||
/// </summary>
|
||||
internal static string Error_NotWebSocketRequest {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_NotWebSocketRequest", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Forbidden: SignalR cross domain is disabled..
|
||||
/// </summary>
|
||||
internal static string Forbidden_CrossDomainIsDisabled {
|
||||
get {
|
||||
return ResourceManager.GetString("Forbidden_CrossDomainIsDisabled", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Error_NoConfiguration" xml:space="preserve">
|
||||
<value>A configuration object must be specified.</value>
|
||||
</data>
|
||||
<data name="Error_NoDepenendeyResolver" xml:space="preserve">
|
||||
<value>A dependency resolver must be specified.</value>
|
||||
</data>
|
||||
<data name="Error_NotWebSocketRequest" xml:space="preserve">
|
||||
<value>Not a valid web socket request.</value>
|
||||
</data>
|
||||
<data name="Forbidden_CrossDomainIsDisabled" xml:space="preserve">
|
||||
<value>Forbidden: SignalR cross domain is disabled.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,237 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Microsoft.AspNet.SignalR.Owin.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin
|
||||
{
|
||||
public partial class ServerRequest
|
||||
{
|
||||
private readonly IDictionary<string, object> _environment;
|
||||
|
||||
public static readonly string OwinEnvironmentKey = "owin.environment";
|
||||
|
||||
public ServerRequest(IDictionary<string, object> environment)
|
||||
{
|
||||
_environment = environment;
|
||||
|
||||
Items = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ OwinEnvironmentKey , _environment }
|
||||
};
|
||||
}
|
||||
|
||||
private string RequestMethod
|
||||
{
|
||||
get { return _environment.Get<string>(OwinConstants.RequestMethod); }
|
||||
}
|
||||
|
||||
public IDictionary<string, string[]> RequestHeaders
|
||||
{
|
||||
get { return _environment.Get<IDictionary<string, string[]>>(OwinConstants.RequestHeaders); }
|
||||
}
|
||||
|
||||
private Stream RequestBody
|
||||
{
|
||||
get { return _environment.Get<Stream>(OwinConstants.RequestBody); }
|
||||
}
|
||||
|
||||
private string RequestScheme
|
||||
{
|
||||
get { return _environment.Get<string>(OwinConstants.RequestScheme); }
|
||||
}
|
||||
|
||||
private string RequestPathBase
|
||||
{
|
||||
get { return _environment.Get<string>(OwinConstants.RequestPathBase); }
|
||||
}
|
||||
|
||||
private string RequestPath
|
||||
{
|
||||
get { return _environment.Get<string>(OwinConstants.RequestPath); }
|
||||
}
|
||||
|
||||
private string RequestQueryString
|
||||
{
|
||||
get { return _environment.Get<string>(OwinConstants.RequestQueryString); }
|
||||
}
|
||||
|
||||
public Action DisableRequestCompression
|
||||
{
|
||||
get { return _environment.Get<Action>(OwinConstants.DisableRequestCompression) ?? (() => { }); }
|
||||
}
|
||||
|
||||
private bool TryParseHostHeader(out IPAddress address, out string host, out int port)
|
||||
{
|
||||
address = null;
|
||||
host = null;
|
||||
port = -1;
|
||||
|
||||
var hostHeader = RequestHeaders.GetHeader("Host");
|
||||
if (String.IsNullOrWhiteSpace(hostHeader))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// IPv6 (http://www.ietf.org/rfc/rfc2732.txt)
|
||||
if (hostHeader.StartsWith("[", StringComparison.Ordinal))
|
||||
{
|
||||
var portIndex = hostHeader.LastIndexOf("]:", StringComparison.Ordinal);
|
||||
if (portIndex != -1 && Int32.TryParse(hostHeader.Substring(portIndex + 2), out port))
|
||||
{
|
||||
if (IPAddress.TryParse(hostHeader.Substring(1, portIndex - 1), out address))
|
||||
{
|
||||
host = null;
|
||||
return true;
|
||||
}
|
||||
host = hostHeader.Substring(0, portIndex + 1);
|
||||
return true;
|
||||
}
|
||||
if (hostHeader.EndsWith("]", StringComparison.Ordinal))
|
||||
{
|
||||
if (IPAddress.TryParse(hostHeader.Substring(1, hostHeader.Length - 2), out address))
|
||||
{
|
||||
host = null;
|
||||
port = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// IPAddresses
|
||||
if (IPAddress.TryParse(hostHeader, out address))
|
||||
{
|
||||
host = null;
|
||||
port = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
var portIndex = hostHeader.LastIndexOf(':');
|
||||
if (portIndex != -1 && Int32.TryParse(hostHeader.Substring(portIndex + 1), out port))
|
||||
{
|
||||
host = hostHeader.Substring(0, portIndex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Plain
|
||||
host = hostHeader;
|
||||
return true;
|
||||
}
|
||||
|
||||
private string RequestHost
|
||||
{
|
||||
get
|
||||
{
|
||||
IPAddress address;
|
||||
string host;
|
||||
int port;
|
||||
if (TryParseHostHeader(out address, out host, out port))
|
||||
{
|
||||
return host ?? address.ToString();
|
||||
}
|
||||
return _environment.Get<string>(OwinConstants.LocalIpAddress) ?? IPAddress.Loopback.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private int RequestPort
|
||||
{
|
||||
get
|
||||
{
|
||||
IPAddress address;
|
||||
string host;
|
||||
int port;
|
||||
if (TryParseHostHeader(out address, out host, out port))
|
||||
{
|
||||
if (port == -1)
|
||||
{
|
||||
return DefaultPort;
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
var portString = _environment.Get<string>(OwinConstants.LocalPort);
|
||||
if (Int32.TryParse(portString, out port) && port != 0)
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
return DefaultPort;
|
||||
}
|
||||
}
|
||||
|
||||
private int DefaultPort
|
||||
{
|
||||
get
|
||||
{
|
||||
return String.Equals(RequestScheme, "https", StringComparison.OrdinalIgnoreCase) ? 443 : 80;
|
||||
}
|
||||
}
|
||||
|
||||
private string ContentType
|
||||
{
|
||||
get
|
||||
{
|
||||
return RequestHeaders.GetHeader("Content-Type");
|
||||
}
|
||||
}
|
||||
|
||||
private string MediaType
|
||||
{
|
||||
get
|
||||
{
|
||||
var contentType = ContentType;
|
||||
if (contentType == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var delimiterPos = contentType.IndexOfAny(CommaSemicolon);
|
||||
return delimiterPos < 0 ? contentType : contentType.Substring(0, delimiterPos);
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasFormData
|
||||
{
|
||||
get
|
||||
{
|
||||
var mediaType = MediaType;
|
||||
return (RequestMethod == "POST" && String.IsNullOrEmpty(mediaType))
|
||||
|| mediaType == "application/x-www-form-urlencoded"
|
||||
|| mediaType == "multipart/form-data";
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasParseableData
|
||||
{
|
||||
get
|
||||
{
|
||||
var mediaType = MediaType;
|
||||
return mediaType == "application/x-www-form-urlencoded"
|
||||
|| mediaType == "multipart/form-data";
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, string>> ReadForm()
|
||||
{
|
||||
if (!HasFormData && !HasParseableData)
|
||||
{
|
||||
return Enumerable.Empty<KeyValuePair<string, string>>();
|
||||
}
|
||||
|
||||
var body = RequestBody;
|
||||
if (body.CanSeek)
|
||||
{
|
||||
body.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
var text = new StreamReader(body).ReadToEnd();
|
||||
return ParamDictionary.ParseToEnumerable(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.SignalR.Owin.Infrastructure;
|
||||
using Microsoft.AspNet.SignalR.Hosting;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin
|
||||
{
|
||||
using WebSocketFunc = Func<IDictionary<string, object>, Task>;
|
||||
public partial class ServerRequest :
|
||||
#if NET45
|
||||
IWebSocketRequest
|
||||
#else
|
||||
IRequest
|
||||
#endif
|
||||
{
|
||||
private static readonly char[] CommaSemicolon = new[] { ',', ';' };
|
||||
|
||||
private Uri _url;
|
||||
private NameValueCollection _queryString;
|
||||
private NameValueCollection _headers;
|
||||
private NameValueCollection _form;
|
||||
private bool _formInitialized;
|
||||
private object _formLock = new object();
|
||||
private IDictionary<string, Cookie> _cookies;
|
||||
|
||||
public Uri Url
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(
|
||||
ref _url, () =>
|
||||
{
|
||||
var uriBuilder = new UriBuilder(RequestScheme, RequestHost, RequestPort, RequestPathBase + RequestPath);
|
||||
if (!String.IsNullOrEmpty(RequestQueryString))
|
||||
{
|
||||
uriBuilder.Query = RequestQueryString;
|
||||
}
|
||||
return uriBuilder.Uri;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public NameValueCollection QueryString
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(
|
||||
ref _queryString, () =>
|
||||
{
|
||||
var collection = new NameValueCollection();
|
||||
foreach (var kv in ParamDictionary.ParseToEnumerable(RequestQueryString))
|
||||
{
|
||||
collection.Add(kv.Key, kv.Value);
|
||||
}
|
||||
return collection;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public NameValueCollection Headers
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(
|
||||
ref _headers, () =>
|
||||
{
|
||||
var collection = new NameValueCollection();
|
||||
foreach (var kv in RequestHeaders)
|
||||
{
|
||||
if (kv.Value != null)
|
||||
{
|
||||
for (var index = 0; index != kv.Value.Length; ++index)
|
||||
{
|
||||
collection.Add(kv.Key, kv.Value[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public NameValueCollection Form
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(
|
||||
ref _form, ref _formInitialized, ref _formLock, () =>
|
||||
{
|
||||
var collection = new NameValueCollection();
|
||||
foreach (var kv in ReadForm())
|
||||
{
|
||||
collection.Add(kv.Key, kv.Value);
|
||||
}
|
||||
return collection;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public IDictionary<string, Cookie> Cookies
|
||||
{
|
||||
get
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(
|
||||
ref _cookies, () =>
|
||||
{
|
||||
var cookies = new Dictionary<string, Cookie>(StringComparer.OrdinalIgnoreCase);
|
||||
var text = RequestHeaders.GetHeader("Cookie");
|
||||
foreach (var kv in ParamDictionary.ParseToEnumerable(text, CommaSemicolon))
|
||||
{
|
||||
if (!cookies.ContainsKey(kv.Key))
|
||||
{
|
||||
cookies.Add(kv.Key, new Cookie(kv.Key, kv.Value));
|
||||
}
|
||||
}
|
||||
return cookies;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public IPrincipal User
|
||||
{
|
||||
get { return _environment.Get<IPrincipal>(OwinConstants.User); }
|
||||
}
|
||||
|
||||
|
||||
public IDictionary<string, object> Items
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
#if NET45
|
||||
public Task AcceptWebSocketRequest(Func<IWebSocket, Task> callback)
|
||||
{
|
||||
var accept = _environment.Get<Action<IDictionary<string, object>, WebSocketFunc>>(OwinConstants.WebSocketAccept);
|
||||
if (accept == null)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.Error_NotWebSocketRequest);
|
||||
}
|
||||
|
||||
var handler = new OwinWebSocketHandler(callback);
|
||||
accept(null, handler.ProcessRequestAsync);
|
||||
return TaskAsyncHelper.Empty;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.SignalR.Hosting;
|
||||
using Microsoft.AspNet.SignalR.Owin.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNet.SignalR.Owin
|
||||
{
|
||||
public partial class ServerResponse : IResponse
|
||||
{
|
||||
private readonly CancellationToken _callCancelled;
|
||||
private readonly IDictionary<string, object> _environment;
|
||||
private Stream _responseBody;
|
||||
|
||||
public ServerResponse(IDictionary<string, object> environment)
|
||||
{
|
||||
_environment = environment;
|
||||
_callCancelled = _environment.Get<CancellationToken>(OwinConstants.CallCancelled);
|
||||
}
|
||||
|
||||
public CancellationToken CancellationToken
|
||||
{
|
||||
get { return _callCancelled; }
|
||||
}
|
||||
|
||||
public string ContentType
|
||||
{
|
||||
get { return ResponseHeaders.GetHeader("Content-Type"); }
|
||||
set { ResponseHeaders.SetHeader("Content-Type", value); }
|
||||
}
|
||||
|
||||
public void Write(ArraySegment<byte> data)
|
||||
{
|
||||
ResponseBody.Write(data.Array, data.Offset, data.Count);
|
||||
}
|
||||
|
||||
public Task Flush()
|
||||
{
|
||||
#if NET45
|
||||
return ResponseBody.FlushAsync();
|
||||
#else
|
||||
return TaskAsyncHelper.FromMethod(() => ResponseBody.Flush());
|
||||
#endif
|
||||
}
|
||||
|
||||
public Task End()
|
||||
{
|
||||
return TaskAsyncHelper.Empty;
|
||||
}
|
||||
|
||||
public IDictionary<string, string[]> ResponseHeaders
|
||||
{
|
||||
get { return _environment.Get<IDictionary<string, string[]>>(OwinConstants.ResponseHeaders); }
|
||||
}
|
||||
|
||||
public Stream ResponseBody
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_responseBody == null)
|
||||
{
|
||||
_responseBody = _environment.Get<Stream>(OwinConstants.ResponseBody);
|
||||
}
|
||||
|
||||
return _responseBody;
|
||||
}
|
||||
}
|
||||
|
||||
public Action DisableResponseBuffering
|
||||
{
|
||||
get { return _environment.Get<Action>(OwinConstants.DisableResponseBuffering) ?? (() => { }); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Owin" version="1.0" targetFramework="net40" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user