update portable projects

This commit is contained in:
Luke Pulverenti
2016-11-08 13:44:23 -05:00
parent 05a5ce58a9
commit a8b340cbb2
84 changed files with 1055 additions and 921 deletions

View File

@@ -0,0 +1,12 @@
using SocketHttpListener.Net;
namespace Emby.Server.Implementations.HttpServer.SocketSharp
{
public static class Extensions
{
public static string GetOperationName(this HttpListenerRequest request)
{
return request.Url.Segments[request.Url.Segments.Length - 1];
}
}
}

View File

@@ -0,0 +1,166 @@
using MediaBrowser.Common.Events;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
using WebSocketState = MediaBrowser.Model.Net.WebSocketState;
namespace Emby.Server.Implementations.HttpServer.SocketSharp
{
public class SharpWebSocket : IWebSocket
{
/// <summary>
/// The logger
/// </summary>
private readonly ILogger _logger;
public event EventHandler<EventArgs> Closed;
/// <summary>
/// Gets or sets the web socket.
/// </summary>
/// <value>The web socket.</value>
private SocketHttpListener.WebSocket WebSocket { get; set; }
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger)
{
if (socket == null)
{
throw new ArgumentNullException("socket");
}
if (logger == null)
{
throw new ArgumentNullException("logger");
}
_logger = logger;
WebSocket = socket;
socket.OnMessage += socket_OnMessage;
socket.OnClose += socket_OnClose;
socket.OnError += socket_OnError;
WebSocket.ConnectAsServer();
}
void socket_OnError(object sender, SocketHttpListener.ErrorEventArgs e)
{
_logger.Error("Error in SharpWebSocket: {0}", e.Message ?? string.Empty);
//EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger);
}
void socket_OnClose(object sender, SocketHttpListener.CloseEventArgs e)
{
EventHelper.FireEventIfNotNull(Closed, this, EventArgs.Empty, _logger);
}
void socket_OnMessage(object sender, SocketHttpListener.MessageEventArgs e)
{
//if (!string.IsNullOrWhiteSpace(e.Data))
//{
// if (OnReceive != null)
// {
// OnReceive(e.Data);
// }
// return;
//}
if (OnReceiveBytes != null)
{
OnReceiveBytes(e.RawData);
}
}
/// <summary>
/// Gets or sets the state.
/// </summary>
/// <value>The state.</value>
public WebSocketState State
{
get
{
WebSocketState commonState;
if (!Enum.TryParse(WebSocket.ReadyState.ToString(), true, out commonState))
{
_logger.Warn("Unrecognized WebSocketState: {0}", WebSocket.ReadyState.ToString());
}
return commonState;
}
}
/// <summary>
/// Sends the async.
/// </summary>
/// <param name="bytes">The bytes.</param>
/// <param name="endOfMessage">if set to <c>true</c> [end of message].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken)
{
var completionSource = new TaskCompletionSource<bool>();
WebSocket.SendAsync(bytes, res => completionSource.TrySetResult(true));
return completionSource.Task;
}
/// <summary>
/// Sends the asynchronous.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="endOfMessage">if set to <c>true</c> [end of message].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken)
{
var completionSource = new TaskCompletionSource<bool>();
WebSocket.SendAsync(text, res => completionSource.TrySetResult(true));
return completionSource.Task;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(true);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool dispose)
{
if (dispose)
{
WebSocket.OnMessage -= socket_OnMessage;
WebSocket.OnClose -= socket_OnClose;
WebSocket.OnError -= socket_OnError;
_cancellationTokenSource.Cancel();
WebSocket.Close();
}
}
/// <summary>
/// Gets or sets the receive action.
/// </summary>
/// <value>The receive action.</value>
public Action<byte[]> OnReceiveBytes { get; set; }
/// <summary>
/// Gets or sets the on receive.
/// </summary>
/// <value>The on receive.</value>
public Action<string> OnReceive { get; set; }
}
}

View File

@@ -0,0 +1,203 @@
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Logging;
using SocketHttpListener.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Emby.Server.Implementations.Logging;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Text;
using SocketHttpListener.Primitives;
namespace Emby.Server.Implementations.HttpServer.SocketSharp
{
public class WebSocketSharpListener : IHttpListener
{
private HttpListener _listener;
private readonly ILogger _logger;
private readonly ICertificate _certificate;
private readonly IMemoryStreamFactory _memoryStreamProvider;
private readonly ITextEncoding _textEncoding;
private readonly INetworkManager _networkManager;
private readonly ISocketFactory _socketFactory;
private readonly ICryptoProvider _cryptoProvider;
private readonly IStreamFactory _streamFactory;
private readonly Func<HttpListenerContext, IHttpRequest> _httpRequestFactory;
public WebSocketSharpListener(ILogger logger, ICertificate certificate, IMemoryStreamFactory memoryStreamProvider, ITextEncoding textEncoding, INetworkManager networkManager, ISocketFactory socketFactory, ICryptoProvider cryptoProvider, IStreamFactory streamFactory, Func<HttpListenerContext, IHttpRequest> httpRequestFactory)
{
_logger = logger;
_certificate = certificate;
_memoryStreamProvider = memoryStreamProvider;
_textEncoding = textEncoding;
_networkManager = networkManager;
_socketFactory = socketFactory;
_cryptoProvider = cryptoProvider;
_streamFactory = streamFactory;
_httpRequestFactory = httpRequestFactory;
}
public Action<Exception, IRequest> ErrorHandler { get; set; }
public Func<IHttpRequest, Uri, Task> RequestHandler { get; set; }
public Action<WebSocketConnectingEventArgs> WebSocketConnecting { get; set; }
public Action<WebSocketConnectEventArgs> WebSocketConnected { get; set; }
public void Start(IEnumerable<string> urlPrefixes)
{
if (_listener == null)
_listener = new HttpListener(new PatternsLogger(_logger), _cryptoProvider, _streamFactory, _socketFactory, _networkManager, _textEncoding, _memoryStreamProvider);
if (_certificate != null)
{
_listener.LoadCert(_certificate);
}
foreach (var prefix in urlPrefixes)
{
_logger.Info("Adding HttpListener prefix " + prefix);
_listener.Prefixes.Add(prefix);
}
_listener.OnContext = ProcessContext;
_listener.Start();
}
private void ProcessContext(HttpListenerContext context)
{
Task.Factory.StartNew(() => InitTask(context));
}
private Task InitTask(HttpListenerContext context)
{
IHttpRequest httpReq = null;
var request = context.Request;
try
{
if (request.IsWebSocketRequest)
{
LoggerUtils.LogRequest(_logger, request);
ProcessWebSocketRequest(context);
return Task.FromResult(true);
}
httpReq = GetRequest(context);
}
catch (Exception ex)
{
_logger.ErrorException("Error processing request", ex);
httpReq = httpReq ?? GetRequest(context);
ErrorHandler(ex, httpReq);
return Task.FromResult(true);
}
return RequestHandler(httpReq, request.Url);
}
private void ProcessWebSocketRequest(HttpListenerContext ctx)
{
try
{
var endpoint = ctx.Request.RemoteEndPoint.ToString();
var url = ctx.Request.RawUrl;
var connectingArgs = new WebSocketConnectingEventArgs
{
Url = url,
QueryString = ctx.Request.QueryString,
Endpoint = endpoint
};
if (WebSocketConnecting != null)
{
WebSocketConnecting(connectingArgs);
}
if (connectingArgs.AllowConnection)
{
_logger.Debug("Web socket connection allowed");
var webSocketContext = ctx.AcceptWebSocket(null);
if (WebSocketConnected != null)
{
WebSocketConnected(new WebSocketConnectEventArgs
{
Url = url,
QueryString = ctx.Request.QueryString,
WebSocket = new SharpWebSocket(webSocketContext.WebSocket, _logger),
Endpoint = endpoint
});
}
}
else
{
_logger.Warn("Web socket connection not allowed");
ctx.Response.StatusCode = 401;
ctx.Response.Close();
}
}
catch (Exception ex)
{
_logger.ErrorException("AcceptWebSocketAsync error", ex);
ctx.Response.StatusCode = 500;
ctx.Response.Close();
}
}
private IHttpRequest GetRequest(HttpListenerContext httpContext)
{
return _httpRequestFactory(httpContext);
}
public void Stop()
{
if (_listener != null)
{
foreach (var prefix in _listener.Prefixes.ToList())
{
_listener.Prefixes.Remove(prefix);
}
_listener.Close();
}
}
public void Dispose()
{
Dispose(true);
}
private bool _disposed;
private readonly object _disposeLock = new object();
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
lock (_disposeLock)
{
if (_disposed) return;
if (disposing)
{
Stop();
}
//release unmanaged resources here...
_disposed = true;
}
}
}
}

View File

@@ -0,0 +1,204 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using MediaBrowser.Model.Logging;
using HttpListenerResponse = SocketHttpListener.Net.HttpListenerResponse;
using IHttpResponse = MediaBrowser.Model.Services.IHttpResponse;
using IRequest = MediaBrowser.Model.Services.IRequest;
namespace Emby.Server.Implementations.HttpServer.SocketSharp
{
public class WebSocketSharpResponse : IHttpResponse
{
private readonly ILogger _logger;
private readonly HttpListenerResponse _response;
public WebSocketSharpResponse(ILogger logger, HttpListenerResponse response, IRequest request)
{
_logger = logger;
this._response = response;
Items = new Dictionary<string, object>();
Request = request;
}
public IRequest Request { get; private set; }
public bool UseBufferedStream { get; set; }
public Dictionary<string, object> Items { get; private set; }
public object OriginalResponse
{
get { return _response; }
}
public int StatusCode
{
get { return this._response.StatusCode; }
set { this._response.StatusCode = value; }
}
public string StatusDescription
{
get { return this._response.StatusDescription; }
set { this._response.StatusDescription = value; }
}
public string ContentType
{
get { return _response.ContentType; }
set { _response.ContentType = value; }
}
//public ICookies Cookies { get; set; }
public void AddHeader(string name, string value)
{
if (string.Equals(name, "Content-Type", StringComparison.OrdinalIgnoreCase))
{
ContentType = value;
return;
}
_response.AddHeader(name, value);
}
public string GetHeader(string name)
{
return _response.Headers[name];
}
public void Redirect(string url)
{
_response.Redirect(url);
}
public Stream OutputStream
{
get { return _response.OutputStream; }
}
public object Dto { get; set; }
public void Write(string text)
{
var bOutput = System.Text.Encoding.UTF8.GetBytes(text);
_response.ContentLength64 = bOutput.Length;
var outputStream = _response.OutputStream;
outputStream.Write(bOutput, 0, bOutput.Length);
Close();
}
public void Close()
{
if (!this.IsClosed)
{
this.IsClosed = true;
try
{
CloseOutputStream(this._response);
}
catch (Exception ex)
{
_logger.ErrorException("Error closing HttpListener output stream", ex);
}
}
}
public void CloseOutputStream(HttpListenerResponse response)
{
try
{
response.OutputStream.Flush();
response.OutputStream.Dispose();
response.Close();
}
catch (Exception ex)
{
_logger.ErrorException("Error in HttpListenerResponseWrapper: " + ex.Message, ex);
}
}
public void End()
{
Close();
}
public void Flush()
{
_response.OutputStream.Flush();
}
public bool IsClosed
{
get;
private set;
}
public void SetContentLength(long contentLength)
{
//you can happily set the Content-Length header in Asp.Net
//but HttpListener will complain if you do - you have to set ContentLength64 on the response.
//workaround: HttpListener throws "The parameter is incorrect" exceptions when we try to set the Content-Length header
_response.ContentLength64 = contentLength;
}
public void SetCookie(Cookie cookie)
{
var cookieStr = AsHeaderValue(cookie);
_response.Headers.Add("Set-Cookie", cookieStr);
}
public static string AsHeaderValue(Cookie cookie)
{
var defaultExpires = DateTime.MinValue;
var path = cookie.Expires == defaultExpires
? "/"
: cookie.Path ?? "/";
var sb = new StringBuilder();
sb.Append($"{cookie.Name}={cookie.Value};path={path}");
if (cookie.Expires != defaultExpires)
{
sb.Append($";expires={cookie.Expires:R}");
}
if (!string.IsNullOrEmpty(cookie.Domain))
{
sb.Append($";domain={cookie.Domain}");
}
//else if (restrictAllCookiesToDomain != null)
//{
// sb.Append($";domain={restrictAllCookiesToDomain}");
//}
if (cookie.Secure)
{
sb.Append(";Secure");
}
if (cookie.HttpOnly)
{
sb.Append(";HttpOnly");
}
return sb.ToString();
}
public bool SendChunked
{
get { return _response.SendChunked; }
set { _response.SendChunked = value; }
}
public bool KeepAlive { get; set; }
public void ClearCookies()
{
}
}
}