2014-07-26 17:30:15 +00:00
using Funq ;
2013-12-07 15:52:38 +00:00
using MediaBrowser.Common ;
using MediaBrowser.Common.Extensions ;
2015-06-13 04:14:48 +00:00
using MediaBrowser.Controller.Configuration ;
2013-12-07 15:52:38 +00:00
using MediaBrowser.Controller.Net ;
using MediaBrowser.Model.Logging ;
2014-07-19 01:28:40 +00:00
using MediaBrowser.Server.Implementations.HttpServer.SocketSharp ;
2013-12-07 15:52:38 +00:00
using ServiceStack ;
using ServiceStack.Host ;
using ServiceStack.Host.Handlers ;
using ServiceStack.Logging ;
using ServiceStack.Web ;
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Reflection ;
using System.Threading ;
using System.Threading.Tasks ;
2015-12-14 14:45:42 +00:00
using MediaBrowser.Common.Net ;
2015-10-30 17:00:33 +00:00
using MediaBrowser.Common.Security ;
2016-10-26 06:01:42 +00:00
using MediaBrowser.Controller ;
2016-03-18 03:40:15 +00:00
using MediaBrowser.Model.Extensions ;
2016-10-23 19:14:57 +00:00
using MediaBrowser.Model.IO ;
2016-10-25 19:02:04 +00:00
using MediaBrowser.Model.Services ;
using ServiceStack.Api.Swagger ;
2013-12-07 15:52:38 +00:00
namespace MediaBrowser.Server.Implementations.HttpServer
{
public class HttpListenerHost : ServiceStackHost , IHttpServer
{
private string DefaultRedirectPath { get ; set ; }
private readonly ILogger _logger ;
2014-01-09 04:44:51 +00:00
public IEnumerable < string > UrlPrefixes { get ; private set ; }
2013-12-07 15:52:38 +00:00
2016-10-26 06:01:42 +00:00
private readonly List < IService > _restServices = new List < IService > ( ) ;
2013-12-07 15:52:38 +00:00
2014-07-18 22:14:59 +00:00
private IHttpListener _listener ;
2013-12-07 15:52:38 +00:00
private readonly ContainerAdapter _containerAdapter ;
public event EventHandler < WebSocketConnectEventArgs > WebSocketConnected ;
2015-03-08 19:48:30 +00:00
public event EventHandler < WebSocketConnectingEventArgs > WebSocketConnecting ;
2013-12-07 15:52:38 +00:00
2015-01-19 04:29:57 +00:00
public string CertificatePath { get ; private set ; }
2015-01-07 03:36:42 +00:00
2015-06-13 04:14:48 +00:00
private readonly IServerConfigurationManager _config ;
2015-12-14 14:45:42 +00:00
private readonly INetworkManager _networkManager ;
2016-10-06 18:55:01 +00:00
private readonly IMemoryStreamProvider _memoryStreamProvider ;
2015-06-13 04:14:48 +00:00
2016-10-26 06:01:42 +00:00
private readonly IServerApplicationHost _appHost ;
public HttpListenerHost ( IServerApplicationHost applicationHost ,
2015-10-30 17:00:33 +00:00
ILogManager logManager ,
2015-06-13 04:14:48 +00:00
IServerConfigurationManager config ,
2015-01-17 19:30:23 +00:00
string serviceName ,
2016-10-06 18:55:01 +00:00
string defaultRedirectPath , INetworkManager networkManager , IMemoryStreamProvider memoryStreamProvider , params Assembly [ ] assembliesWithServices )
2013-12-07 15:52:38 +00:00
: base ( serviceName , assembliesWithServices )
{
2016-10-26 06:01:42 +00:00
_appHost = applicationHost ;
2013-12-07 15:52:38 +00:00
DefaultRedirectPath = defaultRedirectPath ;
2015-12-14 14:45:42 +00:00
_networkManager = networkManager ;
2016-10-06 18:55:01 +00:00
_memoryStreamProvider = memoryStreamProvider ;
2015-06-13 04:14:48 +00:00
_config = config ;
2013-12-07 15:52:38 +00:00
_logger = logManager . GetLogger ( "HttpServer" ) ;
_containerAdapter = new ContainerAdapter ( applicationHost ) ;
}
2015-09-13 23:07:54 +00:00
public string GlobalResponse { get ; set ; }
2015-10-30 17:00:33 +00:00
2013-12-07 15:52:38 +00:00
public override void Configure ( Container container )
{
HostConfig . Instance . DefaultRedirectPath = DefaultRedirectPath ;
2016-07-30 17:52:06 +00:00
HostConfig . Instance . LogUnobservedTaskExceptions = false ;
2013-12-07 15:52:38 +00:00
HostConfig . Instance . MapExceptionToStatusCode = new Dictionary < Type , int >
{
2016-08-31 19:17:11 +00:00
{ typeof ( InvalidOperationException ) , 500 } ,
{ typeof ( NotImplementedException ) , 500 } ,
2013-12-07 15:52:38 +00:00
{ typeof ( ResourceNotFoundException ) , 404 } ,
{ typeof ( FileNotFoundException ) , 404 } ,
2014-07-22 01:29:06 +00:00
{ typeof ( DirectoryNotFoundException ) , 404 } ,
2014-11-15 02:31:03 +00:00
{ typeof ( SecurityException ) , 401 } ,
2015-10-30 17:00:33 +00:00
{ typeof ( PaymentRequiredException ) , 402 } ,
{ typeof ( UnauthorizedAccessException ) , 500 } ,
2016-08-31 19:17:11 +00:00
{ typeof ( ApplicationException ) , 500 } ,
{ typeof ( PlatformNotSupportedException ) , 500 } ,
{ typeof ( NotSupportedException ) , 500 }
2013-12-07 15:52:38 +00:00
} ;
2016-08-08 04:35:21 +00:00
HostConfig . Instance . GlobalResponseHeaders = new Dictionary < string , string > ( ) ;
2016-07-30 17:52:06 +00:00
HostConfig . Instance . DebugMode = false ;
2013-12-07 15:52:38 +00:00
HostConfig . Instance . LogFactory = LogManager . LogFactory ;
2016-10-08 05:57:38 +00:00
HostConfig . Instance . AllowJsonpRequests = false ;
2013-12-07 15:52:38 +00:00
// The Markdown feature causes slow startup times (5 mins+) on cold boots for some users
// Custom format allows images
2016-10-08 05:57:38 +00:00
HostConfig . Instance . EnableFeatures = Feature . Html | Feature . Json | Feature . Xml | Feature . CustomFormat ;
2013-12-07 15:52:38 +00:00
container . Adapter = _containerAdapter ;
2016-10-13 15:07:21 +00:00
Plugins . Add ( new SwaggerFeature ( ) ) ;
2015-07-10 03:00:03 +00:00
Plugins . Add ( new CorsFeature ( allowedHeaders : "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization" ) ) ;
2014-07-02 04:57:18 +00:00
2014-07-09 00:46:11 +00:00
//Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {
// new SessionAuthProvider(_containerAdapter.Resolve<ISessionContext>()),
//}));
2014-07-02 04:57:18 +00:00
2016-09-01 16:36:11 +00:00
//PreRequestFilters.Add((httpReq, httpRes) =>
//{
// //Handles Request and closes Responses after emitting global HTTP Headers
// if (string.Equals(httpReq.Verb, "OPTIONS", StringComparison.OrdinalIgnoreCase))
// {
// httpRes.EndRequest(); //add a 'using ServiceStack;'
// }
//});
2014-08-18 03:00:37 +00:00
2016-10-26 06:01:42 +00:00
var requestFilters = _appHost . GetExports < IRequestFilter > ( ) . ToList ( ) ;
foreach ( var filter in requestFilters )
{
HostContext . GlobalRequestFilters . Add ( filter . Filter ) ;
}
2016-05-29 21:04:49 +00:00
HostContext . GlobalResponseFilters . Add ( new ResponseFilter ( _logger ) . FilterResponse ) ;
2013-12-07 15:52:38 +00:00
}
public override void OnAfterInit ( )
{
SetAppDomainData ( ) ;
base . OnAfterInit ( ) ;
}
public override void OnConfigLoad ( )
{
base . OnConfigLoad ( ) ;
2015-01-17 19:30:23 +00:00
Config . HandlerFactoryPath = null ;
2013-12-07 15:52:38 +00:00
2015-01-17 19:30:23 +00:00
Config . MetadataRedirectPath = "metadata" ;
2013-12-07 15:52:38 +00:00
}
protected override ServiceController CreateServiceController ( params Assembly [ ] assembliesWithServices )
{
var types = _restServices . Select ( r = > r . GetType ( ) ) . ToArray ( ) ;
return new ServiceController ( this , ( ) = > types ) ;
}
public virtual void SetAppDomainData ( )
{
//Required for Mono to resolve VirtualPathUtility and Url.Content urls
var domain = Thread . GetDomain ( ) ; // or AppDomain.Current
domain . SetData ( ".appDomain" , "1" ) ;
domain . SetData ( ".appVPath" , "/" ) ;
domain . SetData ( ".appPath" , domain . BaseDirectory ) ;
if ( string . IsNullOrEmpty ( domain . GetData ( ".appId" ) as string ) )
{
domain . SetData ( ".appId" , "1" ) ;
}
if ( string . IsNullOrEmpty ( domain . GetData ( ".domainId" ) as string ) )
{
domain . SetData ( ".domainId" , "1" ) ;
}
}
public override ServiceStackHost Start ( string listeningAtUrlBase )
{
2014-07-18 22:14:59 +00:00
StartListener ( ) ;
2013-12-07 15:52:38 +00:00
return this ;
}
/// <summary>
/// Starts the Web Service
/// </summary>
2014-07-18 22:14:59 +00:00
private void StartListener ( )
2013-12-07 15:52:38 +00:00
{
2016-10-25 19:02:04 +00:00
HostContext . Config . HandlerFactoryPath = GetHandlerPathIfAny ( UrlPrefixes . First ( ) ) ;
2014-07-09 00:46:11 +00:00
2014-12-27 22:52:41 +00:00
_listener = GetListener ( ) ;
2014-07-19 01:28:40 +00:00
2015-03-08 19:48:30 +00:00
_listener . WebSocketConnected = OnWebSocketConnected ;
_listener . WebSocketConnecting = OnWebSocketConnecting ;
2014-07-19 01:28:40 +00:00
_listener . ErrorHandler = ErrorHandler ;
_listener . RequestHandler = RequestHandler ;
2013-12-07 15:52:38 +00:00
2014-07-18 22:14:59 +00:00
_listener . Start ( UrlPrefixes ) ;
2014-07-09 00:46:11 +00:00
}
2013-12-07 15:52:38 +00:00
2016-10-25 19:02:04 +00:00
public static string GetHandlerPathIfAny ( string listenerUrl )
{
if ( listenerUrl = = null ) return null ;
var pos = listenerUrl . IndexOf ( "://" , StringComparison . OrdinalIgnoreCase ) ;
if ( pos = = - 1 ) return null ;
var startHostUrl = listenerUrl . Substring ( pos + "://" . Length ) ;
var endPos = startHostUrl . IndexOf ( '/' ) ;
if ( endPos = = - 1 ) return null ;
var endHostUrl = startHostUrl . Substring ( endPos + 1 ) ;
return string . IsNullOrEmpty ( endHostUrl ) ? null : endHostUrl . TrimEnd ( '/' ) ;
}
2014-12-27 22:52:41 +00:00
private IHttpListener GetListener ( )
{
2016-10-06 18:55:01 +00:00
return new WebSocketSharpListener ( _logger , CertificatePath , _memoryStreamProvider ) ;
2014-12-27 22:52:41 +00:00
}
2015-03-08 19:48:30 +00:00
private void OnWebSocketConnecting ( WebSocketConnectingEventArgs args )
{
2016-04-22 16:12:20 +00:00
if ( _disposed )
{
return ;
}
2015-03-08 19:48:30 +00:00
if ( WebSocketConnecting ! = null )
{
WebSocketConnecting ( this , args ) ;
}
}
private void OnWebSocketConnected ( WebSocketConnectEventArgs args )
2014-07-09 00:46:11 +00:00
{
2016-04-22 16:12:20 +00:00
if ( _disposed )
{
return ;
}
2014-07-18 22:14:59 +00:00
if ( WebSocketConnected ! = null )
2014-07-09 00:46:11 +00:00
{
2014-07-18 22:14:59 +00:00
WebSocketConnected ( this , args ) ;
2014-07-09 00:46:11 +00:00
}
2013-12-07 15:52:38 +00:00
}
2014-07-18 22:14:59 +00:00
private void ErrorHandler ( Exception ex , IRequest httpReq )
2013-12-07 15:52:38 +00:00
{
try
{
var httpRes = httpReq . Response ;
2014-07-04 02:22:57 +00:00
if ( httpRes . IsClosed )
{
return ;
}
2015-01-17 19:30:23 +00:00
2014-07-09 00:46:11 +00:00
var errorResponse = new ErrorResponse
{
ResponseStatus = new ResponseStatus
{
ErrorCode = ex . GetType ( ) . GetOperationName ( ) ,
Message = ex . Message ,
2014-10-28 23:17:55 +00:00
StackTrace = ex . StackTrace
2014-07-09 00:46:11 +00:00
}
} ;
2013-12-07 15:52:38 +00:00
var contentType = httpReq . ResponseContentType ;
var serializer = HostContext . ContentTypes . GetResponseSerializer ( contentType ) ;
if ( serializer = = null )
{
contentType = HostContext . Config . DefaultContentType ;
serializer = HostContext . ContentTypes . GetResponseSerializer ( contentType ) ;
}
var httpError = ex as IHttpError ;
if ( httpError ! = null )
{
httpRes . StatusCode = httpError . Status ;
httpRes . StatusDescription = httpError . StatusDescription ;
}
else
{
httpRes . StatusCode = 500 ;
}
httpRes . ContentType = contentType ;
serializer ( httpReq , errorResponse , httpRes ) ;
httpRes . Close ( ) ;
}
2016-08-05 21:15:48 +00:00
catch
2013-12-07 15:52:38 +00:00
{
2016-02-04 18:04:04 +00:00
//_logger.ErrorException("Error this.ProcessRequest(context)(Exception while writing error to the response)", errorEx);
2013-12-07 15:52:38 +00:00
}
}
/// <summary>
/// Shut down the Web Service
/// </summary>
public void Stop ( )
{
2014-07-18 22:14:59 +00:00
if ( _listener ! = null )
2013-12-07 15:52:38 +00:00
{
2014-07-18 22:14:59 +00:00
_listener . Stop ( ) ;
2013-12-07 15:52:38 +00:00
}
}
2016-01-23 03:10:21 +00:00
private readonly Dictionary < string , int > _skipLogExtensions = new Dictionary < string , int > ( StringComparer . OrdinalIgnoreCase )
{
{ ".js" , 0 } ,
{ ".css" , 0 } ,
{ ".woff" , 0 } ,
{ ".woff2" , 0 } ,
{ ".ttf" , 0 } ,
{ ".html" , 0 }
} ;
2016-02-03 21:56:00 +00:00
private bool EnableLogging ( string url , string localPath )
2016-01-23 03:10:21 +00:00
{
2016-02-01 19:54:49 +00:00
var extension = GetExtension ( url ) ;
2016-01-23 03:10:21 +00:00
2016-02-03 21:56:00 +00:00
if ( string . IsNullOrWhiteSpace ( extension ) | | ! _skipLogExtensions . ContainsKey ( extension ) )
{
if ( string . IsNullOrWhiteSpace ( localPath ) | | localPath . IndexOf ( "system/ping" , StringComparison . OrdinalIgnoreCase ) = = - 1 )
{
return true ;
}
}
return false ;
2016-01-23 03:10:21 +00:00
}
2016-02-01 19:54:49 +00:00
private string GetExtension ( string url )
{
var parts = url . Split ( new [ ] { '?' } , 2 ) ;
return Path . GetExtension ( parts [ 0 ] ) ;
}
2016-03-15 19:11:53 +00:00
public static string RemoveQueryStringByKey ( string url , string key )
{
var uri = new Uri ( url ) ;
// this gets all the query string key value pairs as a collection
var newQueryString = MyHttpUtility . ParseQueryString ( uri . Query ) ;
if ( newQueryString . Count = = 0 )
{
return url ;
}
// this removes the key if exists
newQueryString . Remove ( key ) ;
// this gets the page path from root without QueryString
string pagePathWithoutQueryString = uri . GetLeftPart ( UriPartial . Path ) ;
return newQueryString . Count > 0
? String . Format ( "{0}?{1}" , pagePathWithoutQueryString , newQueryString )
: pagePathWithoutQueryString ;
}
private string GetUrlToLog ( string url )
{
url = RemoveQueryStringByKey ( url , "api_key" ) ;
return url ;
}
2016-08-18 06:26:47 +00:00
private string NormalizeConfiguredLocalAddress ( string address )
{
var index = address . Trim ( '/' ) . IndexOf ( '/' ) ;
if ( index ! = - 1 )
{
address = address . Substring ( index + 1 ) ;
}
return address . Trim ( '/' ) ;
}
private bool ValidateHost ( Uri url )
{
var hosts = _config
. Configuration
. LocalNetworkAddresses
. Select ( NormalizeConfiguredLocalAddress )
. ToList ( ) ;
if ( hosts . Count = = 0 )
{
return true ;
}
var host = url . Host ? ? string . Empty ;
_logger . Debug ( "Validating host {0}" , host ) ;
if ( _networkManager . IsInPrivateAddressSpace ( host ) )
{
hosts . Add ( "localhost" ) ;
hosts . Add ( "127.0.0.1" ) ;
return hosts . Any ( i = > host . IndexOf ( i , StringComparison . OrdinalIgnoreCase ) ! = - 1 ) ;
}
return true ;
}
2013-12-07 15:52:38 +00:00
/// <summary>
/// Overridable method that can be used to implement a custom hnandler
/// </summary>
2014-07-18 22:14:59 +00:00
/// <param name="httpReq">The HTTP req.</param>
2014-07-19 01:28:40 +00:00
/// <param name="url">The URL.</param>
2014-07-18 22:14:59 +00:00
/// <returns>Task.</returns>
2016-07-14 19:13:52 +00:00
protected async Task RequestHandler ( IHttpRequest httpReq , Uri url )
2013-12-07 15:52:38 +00:00
{
2014-07-18 22:14:59 +00:00
var date = DateTime . Now ;
2014-07-09 00:46:11 +00:00
2014-07-18 22:14:59 +00:00
var httpRes = httpReq . Response ;
2014-07-09 00:46:11 +00:00
2016-04-22 16:12:20 +00:00
if ( _disposed )
{
httpRes . StatusCode = 503 ;
httpRes . Close ( ) ;
2016-07-14 19:13:52 +00:00
return ;
2016-04-22 16:12:20 +00:00
}
2016-08-18 06:26:47 +00:00
if ( ! ValidateHost ( url ) )
{
httpRes . StatusCode = 400 ;
httpRes . ContentType = "text/plain" ;
httpRes . Write ( "Invalid host" ) ;
httpRes . Close ( ) ;
return ;
}
2016-09-01 16:36:11 +00:00
if ( string . Equals ( httpReq . Verb , "OPTIONS" , StringComparison . OrdinalIgnoreCase ) )
{
httpRes . StatusCode = 200 ;
httpRes . AddHeader ( "Access-Control-Allow-Origin" , "*" ) ;
httpRes . AddHeader ( "Access-Control-Allow-Methods" , "GET, POST, PUT, DELETE, PATCH, OPTIONS" ) ;
httpRes . AddHeader ( "Access-Control-Allow-Headers" , "Content-Type, Authorization, Range, X-MediaBrowser-Token, X-Emby-Authorization" ) ;
httpRes . ContentType = "text/html" ;
httpRes . Close ( ) ;
}
2014-07-18 22:14:59 +00:00
var operationName = httpReq . OperationName ;
var localPath = url . LocalPath ;
2014-07-09 00:46:11 +00:00
2016-01-27 18:35:37 +00:00
var urlString = url . OriginalString ;
2016-02-03 21:56:00 +00:00
var enableLog = EnableLogging ( urlString , localPath ) ;
2016-03-15 19:11:53 +00:00
var urlToLog = urlString ;
2016-01-23 03:10:21 +00:00
if ( enableLog )
{
2016-03-15 19:11:53 +00:00
urlToLog = GetUrlToLog ( urlString ) ;
LoggerUtils . LogRequest ( _logger , urlToLog , httpReq . HttpMethod , httpReq . UserAgent ) ;
2016-01-23 03:10:21 +00:00
}
2016-03-18 03:40:15 +00:00
2016-04-06 02:18:56 +00:00
if ( string . Equals ( localPath , "/emby/" , StringComparison . OrdinalIgnoreCase ) | |
string . Equals ( localPath , "/mediabrowser/" , StringComparison . OrdinalIgnoreCase ) )
{
httpRes . RedirectToUrl ( DefaultRedirectPath ) ;
2016-07-14 19:13:52 +00:00
return ;
2016-04-06 02:18:56 +00:00
}
if ( string . Equals ( localPath , "/emby" , StringComparison . OrdinalIgnoreCase ) | |
string . Equals ( localPath , "/mediabrowser" , StringComparison . OrdinalIgnoreCase ) )
{
httpRes . RedirectToUrl ( "emby/" + DefaultRedirectPath ) ;
2016-07-14 19:13:52 +00:00
return ;
2016-04-06 02:18:56 +00:00
}
2015-04-11 21:34:05 +00:00
if ( string . Equals ( localPath , "/mediabrowser/" , StringComparison . OrdinalIgnoreCase ) | |
2016-03-18 03:40:15 +00:00
string . Equals ( localPath , "/mediabrowser" , StringComparison . OrdinalIgnoreCase ) | |
2016-08-22 18:28:24 +00:00
localPath . IndexOf ( "mediabrowser/web" , StringComparison . OrdinalIgnoreCase ) ! = - 1 )
{
httpRes . StatusCode = 200 ;
httpRes . ContentType = "text/html" ;
var newUrl = urlString . Replace ( "mediabrowser" , "emby" , StringComparison . OrdinalIgnoreCase )
. Replace ( "/dashboard/" , "/web/" , StringComparison . OrdinalIgnoreCase ) ;
if ( ! string . Equals ( newUrl , urlString , StringComparison . OrdinalIgnoreCase ) )
{
httpRes . Write ( "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + newUrl + "\">" + newUrl + "</a></body></html>" ) ;
httpRes . Close ( ) ;
return ;
}
}
if ( localPath . IndexOf ( "dashboard/" , StringComparison . OrdinalIgnoreCase ) ! = - 1 & &
localPath . IndexOf ( "web/dashboard" , StringComparison . OrdinalIgnoreCase ) = = - 1 )
2014-07-09 00:46:11 +00:00
{
2016-03-18 03:40:15 +00:00
httpRes . StatusCode = 200 ;
2016-03-18 06:36:58 +00:00
httpRes . ContentType = "text/html" ;
2016-03-18 03:40:15 +00:00
var newUrl = urlString . Replace ( "mediabrowser" , "emby" , StringComparison . OrdinalIgnoreCase )
. Replace ( "/dashboard/" , "/web/" , StringComparison . OrdinalIgnoreCase ) ;
2016-03-25 17:48:18 +00:00
if ( ! string . Equals ( newUrl , urlString , StringComparison . OrdinalIgnoreCase ) )
{
httpRes . Write ( "<!doctype html><html><head><title>Emby</title></head><body>Please update your Emby bookmark to <a href=\"" + newUrl + "\">" + newUrl + "</a></body></html>" ) ;
2016-03-18 03:40:15 +00:00
2016-03-25 17:48:18 +00:00
httpRes . Close ( ) ;
2016-07-14 19:13:52 +00:00
return ;
2016-03-25 17:48:18 +00:00
}
2014-07-09 00:46:11 +00:00
}
2016-03-18 06:36:58 +00:00
2015-11-14 19:09:49 +00:00
if ( string . Equals ( localPath , "/web" , StringComparison . OrdinalIgnoreCase ) )
{
httpRes . RedirectToUrl ( DefaultRedirectPath ) ;
2016-07-14 19:13:52 +00:00
return ;
2015-11-14 19:09:49 +00:00
}
if ( string . Equals ( localPath , "/web/" , StringComparison . OrdinalIgnoreCase ) )
{
httpRes . RedirectToUrl ( "../" + DefaultRedirectPath ) ;
2016-07-14 19:13:52 +00:00
return ;
2015-11-14 19:09:49 +00:00
}
2014-07-09 00:46:11 +00:00
if ( string . Equals ( localPath , "/" , StringComparison . OrdinalIgnoreCase ) )
{
2015-01-17 19:30:23 +00:00
httpRes . RedirectToUrl ( DefaultRedirectPath ) ;
2016-07-14 19:13:52 +00:00
return ;
2014-07-09 00:46:11 +00:00
}
if ( string . IsNullOrEmpty ( localPath ) )
{
2015-01-17 19:30:23 +00:00
httpRes . RedirectToUrl ( "/" + DefaultRedirectPath ) ;
2016-07-14 19:13:52 +00:00
return ;
2014-07-09 00:46:11 +00:00
}
2016-02-21 06:25:25 +00:00
if ( string . Equals ( localPath , "/emby/pin" , StringComparison . OrdinalIgnoreCase ) )
{
httpRes . RedirectToUrl ( "web/pin.html" ) ;
2016-07-14 19:13:52 +00:00
return ;
2016-02-21 06:25:25 +00:00
}
2016-03-18 06:36:58 +00:00
2015-09-13 23:07:54 +00:00
if ( ! string . IsNullOrWhiteSpace ( GlobalResponse ) )
{
2016-02-15 04:46:51 +00:00
httpRes . StatusCode = 503 ;
httpRes . ContentType = "text/html" ;
httpRes . Write ( GlobalResponse ) ;
2016-02-01 19:54:49 +00:00
2016-02-15 04:46:51 +00:00
httpRes . Close ( ) ;
2016-07-14 19:13:52 +00:00
return ;
2015-09-13 23:07:54 +00:00
}
2013-12-07 15:52:38 +00:00
var handler = HttpHandlerFactory . GetHandler ( httpReq ) ;
2014-07-09 00:46:11 +00:00
var remoteIp = httpReq . RemoteIp ;
2013-12-07 15:52:38 +00:00
var serviceStackHandler = handler as IServiceStackHandler ;
if ( serviceStackHandler ! = null )
{
var restHandler = serviceStackHandler as RestHandler ;
if ( restHandler ! = null )
{
httpReq . OperationName = operationName = restHandler . RestPath . RequestType . GetOperationName ( ) ;
}
2016-07-14 19:13:52 +00:00
try
{
await serviceStackHandler . ProcessRequestAsync ( httpReq , httpRes , operationName ) . ConfigureAwait ( false ) ;
}
finally
2014-07-09 00:46:11 +00:00
{
2016-07-14 19:13:52 +00:00
httpRes . Close ( ) ;
2014-07-19 01:28:40 +00:00
var statusCode = httpRes . StatusCode ;
2014-07-09 00:46:11 +00:00
var duration = DateTime . Now - date ;
2016-01-23 03:10:21 +00:00
if ( enableLog )
{
2016-03-15 19:11:53 +00:00
LoggerUtils . LogResponse ( _logger , statusCode , urlToLog , remoteIp , duration ) ;
2016-01-23 03:10:21 +00:00
}
2016-07-14 19:13:52 +00:00
}
2013-12-07 15:52:38 +00:00
}
2016-10-07 15:08:13 +00:00
else
{
httpRes . Close ( ) ;
}
2013-12-07 15:52:38 +00:00
}
/// <summary>
/// Adds the rest handlers.
/// </summary>
/// <param name="services">The services.</param>
2016-10-26 06:01:42 +00:00
public void Init ( IEnumerable < IService > services )
2013-12-07 15:52:38 +00:00
{
_restServices . AddRange ( services ) ;
ServiceController = CreateServiceController ( ) ;
_logger . Info ( "Calling ServiceStack AppHost.Init" ) ;
2013-12-09 02:24:48 +00:00
base . Init ( ) ;
2013-12-07 15:52:38 +00:00
}
2016-10-25 19:02:04 +00:00
public override Model . Services . RouteAttribute [ ] GetRouteAttributes ( Type requestType )
2015-01-17 19:30:23 +00:00
{
var routes = base . GetRouteAttributes ( requestType ) . ToList ( ) ;
var clone = routes . ToList ( ) ;
foreach ( var route in clone )
{
2016-10-25 19:02:04 +00:00
routes . Add ( new Model . Services . RouteAttribute ( NormalizeEmbyRoutePath ( route . Path ) , route . Verbs )
2015-04-11 21:34:05 +00:00
{
Notes = route . Notes ,
Priority = route . Priority ,
Summary = route . Summary
} ) ;
2016-03-18 03:40:15 +00:00
2016-10-25 19:02:04 +00:00
routes . Add ( new Model . Services . RouteAttribute ( NormalizeRoutePath ( route . Path ) , route . Verbs )
2015-01-17 19:30:23 +00:00
{
Notes = route . Notes ,
Priority = route . Priority ,
Summary = route . Summary
} ) ;
2015-02-19 04:37:44 +00:00
2016-10-25 19:02:04 +00:00
routes . Add ( new Model . Services . RouteAttribute ( DoubleNormalizeEmbyRoutePath ( route . Path ) , route . Verbs )
2015-04-11 21:34:05 +00:00
{
Notes = route . Notes ,
Priority = route . Priority ,
Summary = route . Summary
} ) ;
2015-01-17 19:30:23 +00:00
}
return routes . ToArray ( ) ;
}
2015-04-11 21:34:05 +00:00
private string NormalizeEmbyRoutePath ( string path )
{
if ( path . StartsWith ( "/" , StringComparison . OrdinalIgnoreCase ) )
{
return "/emby" + path ;
}
return "emby/" + path ;
}
private string DoubleNormalizeEmbyRoutePath ( string path )
{
if ( path . StartsWith ( "/" , StringComparison . OrdinalIgnoreCase ) )
{
return "/emby/emby" + path ;
}
return "emby/emby/" + path ;
}
2015-01-17 19:30:23 +00:00
private string NormalizeRoutePath ( string path )
{
if ( path . StartsWith ( "/" , StringComparison . OrdinalIgnoreCase ) )
{
return "/mediabrowser" + path ;
}
return "mediabrowser/" + path ;
}
2014-07-09 00:46:11 +00:00
2013-12-07 15:52:38 +00:00
/// <summary>
/// Releases the specified instance.
/// </summary>
/// <param name="instance">The instance.</param>
public override void Release ( object instance )
{
// Leave this empty so SS doesn't try to dispose our objects
}
private bool _disposed ;
private readonly object _disposeLock = new object ( ) ;
protected virtual void Dispose ( bool disposing )
{
if ( _disposed ) return ;
base . Dispose ( ) ;
lock ( _disposeLock )
{
if ( _disposed ) return ;
if ( disposing )
{
Stop ( ) ;
}
//release unmanaged resources here...
_disposed = true ;
}
}
public override void Dispose ( )
{
Dispose ( true ) ;
GC . SuppressFinalize ( this ) ;
}
2015-01-07 03:36:42 +00:00
public void StartServer ( IEnumerable < string > urlPrefixes , string certificatePath )
2013-12-07 15:52:38 +00:00
{
2015-01-19 04:29:57 +00:00
CertificatePath = certificatePath ;
2014-01-09 04:44:51 +00:00
UrlPrefixes = urlPrefixes . ToList ( ) ;
Start ( UrlPrefixes . First ( ) ) ;
2013-12-07 15:52:38 +00:00
}
}
}