imported signalr 1.1.3 into NzbDrone.

This commit is contained in:
kayone
2013-11-21 21:26:57 -08:00
parent 891443e05d
commit 0e623e7ce4
236 changed files with 20490 additions and 35 deletions
@@ -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);
}
}
}
+99
View File
@@ -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>